【问题标题】:R R6 classes and UseMethod / generic methodsR R6 类和 UseMethod / 泛型方法
【发布时间】:2014-08-05 12:06:44
【问题描述】:

我想使用 R6 类和泛型方法 (UseMethod) 将不同类(Small1、MyClassA 和 Small2、MyClassB)的小对象添加到 MyClass 的 Big 实例内的公共列表(MyListA 和 MyListB)中。

这在创建时有效(Big 是使用 Small1 和 -2 创建的),但之后会失败:

> Big$AddObj(Small3) #produces:
Error in UseMethod("AddObj", x) :    no applicable method for 'AddObj'
 applied to an object of class "c('MyClassA', 'R6')"

我不太确定我的错误是什么。稍后如何为其他对象调用 AddObj-Method?建议将不胜感激。

require('R6')

MyClass <- R6Class("MyClass",
   public = list(
     initialize = function(...) {
       for (x in list(...)) {AddObj(x)}
     },
     AddObj = function(x) {UseMethod("AddObj", x)},
     AddObj.MyClassA = function(x) {
       MyListA <<- c(MyListA, list(x))},
     AddObj.MyClassB = function(x) {
       MyListB <<- c(MyListB, list(x))},
     AddObj.default = function(x) {
       otherObjects <<- c(otherObjects, list(x))},
     Show = function() {
       print(methods(AddObj))
       if (length(MyListA)>0) print(MyListA)
       if (length(MyListB)>0) print(MyListB)
     },
     MyListA = list(),
     MyListB = list(),
     otherObjects = list()
   )
)

MyClassA <- R6Class("MyClassA",
  public = list(
    name = NA,
    initialize = function(input) {
      if (!missing(input)) name <<- as.character(input)}
  ))
MyClassB <- R6Class("MyClassB",
  public = list(
    name = NA,
    initialize = function(input) {
      if (!missing(input)) name <<- as.character(input)}
  ))


Small1 <- MyClassA$new("MyName1")
Small2 <- MyClassB$new("MyName2")
Big <- MyClass$new(Small1, Small2)
Big$Show()

Small3 <- MyClassA$new("MyNewName")
Big$AddObj(Small3)

【问题讨论】:

  • 我找到了一个我不太喜欢的解决方法 - 通过定义另一个函数 (ExternalAddObj) 与 AddObj 的闭包:` ExternalAddObj = function(x) { return(AddObj(x)) },` 从类对象之外的某个地方,使用Big$ExternalAddObj(Small3),它可以工作。不过,有没有更好的方法来做到这一点?

标签: r class oop generics


【解决方案1】:

R6 对象中没有 S3 分派,但您可以像这样使用 if-else 语句:

library('R6')

MyClass <- R6Class("MyClass",
  portable = FALSE,
  public = list(
    initialize = function(...) {
      for (x in list(...)) {AddObj(x)}
    },
    AddObj = function(x) {
      if (inherits(x, "MyClassA"))
        MyListA <<- c(MyListA, list(x))
      else if (inherits(x, "MyClassB"))
        MyListB <<- c(MyListB, list(x))
      else
        otherObjects <<- c(otherObjects, list(x))
    },
    Show = function() {
      if (length(MyListA)>0) print(MyListA)
      if (length(MyListB)>0) print(MyListB)
    },
    MyListA = list(),
    MyListB = list(),
    otherObjects = list()
  )
)

MyClassA <- R6Class("MyClassA",
  portable = FALSE,
  public = list(
    name = NA,
    initialize = function(input) {
      if (!missing(input)) name <<- as.character(input)}
  ))
MyClassB <- R6Class("MyClassB",
  portable = FALSE,
  public = list(
    name = NA,
    initialize = function(input) {
      if (!missing(input)) name <<- as.character(input)}
  ))



Small1 <- MyClassA$new("MyName1")
Small2 <- MyClassB$new("MyName2")
Big <- MyClass$new(Small1, Small2)
Big$Show()

Small3 <- MyClassA$new("MyNewName")
Big$AddObj(Small3)
Big$Show()

另外请注意,我使用了portable=FALSE 设置,这是刚刚添加到 R6 开发版的东西。有关详细信息,请参阅https://github.com/wch/R6/issues/16

更新:事实证明我有点错误——在 R6 对象中存在 S3 调度,但如果使用 $ 调用该函数,则不会使用它,就像在 Big$AddObj(Small3) 中一样。您可以通过eval(quote(AddObj(Small3)), envir = Big) 之类的方式使用它,但这显然不是很好。最好使用 if-else 并使用 inherits()

【讨论】:

  • 谢谢你,温斯顿!是的,我还意识到你必须进入Big 环境才能使用 S3 调度。我还没有决定是选择你的替代方案还是使用 active 对象,它只是调用 AddObj-Routine。我真的很想保留 S3 调度,以防我想在其他地方使用这些功能。 //关于更新:我认为默认的portable=TRUE 行为非常好,使用self$ 实际上相当直观。
  • 嗯,看来我还不能投票给你的答案……当我有足够的分数时会这样做。还是谢谢。
猜你喜欢
  • 2018-01-07
  • 1970-01-01
  • 1970-01-01
  • 2021-02-16
  • 1970-01-01
  • 2012-11-01
  • 1970-01-01
  • 2016-12-24
  • 1970-01-01
相关资源
最近更新 更多