如何为内部泛型方法添加其他参数?

时间:2018-08-16 08:50:47

标签: r oop inheritance methods internal

我想为我的类myClass实现内部通用[<-(〜help(Extract))的插入方法。 在通过[<-将实际的 insetting 传递给NextMethod()之前,此方法应该运行一堆测试。

我了解:

  • 任何方法都必须至少包含泛型的参数(我认为是我的)
  • NextMethod()调用通常不需要任何参数(尽管手动提供它们似乎也无济于事)。

这是我的代表:

x <- c(1,2)
class(x) <- c("myClass", "numeric")

`[<-.myClass` <- function(x, i, j, value, foo = TRUE, ...) {
  if (foo) {
    stop("'foo' must be false!")
  }
  NextMethod()
}

x[1] <- 3  # this errors out with *expected* error message, so dispatch works
x[1, foo = FALSE] <- 3  # this fails with "incorrect number of subscripts

似乎正在发生的事情是,NextMethod() 继续传递foo到内部通用[<-,该错误将foo误认为另一个索引,并因此导致错误(因为在这种情况下,x没有第二维可以索引)。

我还尝试提供明确没有提供NextMethod()的参数,但这也失败了(请参见中断下方的reprex)。

如何避免在方法中添加其他参数而阻塞NextMethod()

(奖金:有人知道构建内部泛型方法的好资源吗?@Hadleys adv-r有点问题)。


使用显式参数表示:

x <- c(1,2)
class(x) <- c("myClass", "numeric")

`[<-.myClass` <- function(x, i = NULL, j = NULL, value, foo = TRUE, ...) {
  if (foo) {
    stop("'foo' must be false!")
  }
  NextMethod(generic = "`[<-`", object = x, i = i, j = j, value = value, ...)
}

x[1] <- 3  # this errors out with expected error message, so dispatch works
x[1, foo = FALSE] <- 3  # this fails with "incorrect number of subscripts

2 个答案:

答案 0 :(得分:5)

除了剥离类(它复制了x之外),我看不到其他简单的方法

`[<-.myClass` <- function(x, i, value, ..., foo = TRUE) {
  if (foo) {
    cat("hi!")
    x
  } else {
    class_x <- class(x)
    x <- unclass(x)
    x[i] <- value
    class(x) <- class_x
    x
  }
}

x <- structure(1:2, class = "myClass")
x[1] <- 3
#> hi!

x[1, foo = FALSE] <- 3
x
#> [1] 3 2
#> attr(,"class")
#> [1] "myClass"

这不是通用方法-仅[[<-等需要,因为它们不使用常规规则进行参数匹配:

  

请注意,这些操作不以标准方式匹配其索引参数:参数名称被忽略,仅使用位置匹配。因此,m[j = 2, i = 1]等效于m[2, 1],而不等效于m[1, 2]

(摘自?`[`中的“参数匹配”部分)

这意味着您的x[1, foo = FALSE]等效于x[1, FALSE],然后您会收到一条错误消息,因为x不是矩阵。

无效的方法:

  • NextMethod()提供附加参数:这只会增加参数数量,而不会减少

  • foorm(foo)解除绑定:这会导致有关未定义的foo的错误。

  • 用丢失的符号替换foo:这会导致错误,没有提供foo,没有默认参数。

答案 1 :(得分:3)

这就是我的理解方式,但是我对这个主题了解不多,所以我希望我不要说太多错误的话。

来自?NextMethod

  

NextMethod调用下一个方法(由类向量确定,   提供给泛型的对象或第一个参数   如果调用了方法,则返回包含NextMethod的函数   直接)。

您的班级向量是:

x <- c(1,2)
class(x) <- "myClass" # note: you might want class(x) <- c("myClass", class(x))
class(x) # [1] "myClass"

因此,这里没有“下一个方法”,并且[<-.default不存在。

如果我们定义它会发生什么?

`[<-.default` <- function(x, i, j, value, ...) {print("default"); value} 

x[1, foo = FALSE] <- 3 
# [1] "default"
x
# [1] 3

如果有一个带有...参数的默认方法,它将像foo参数一样正常工作,但事实并非如此,因此我认为不能调用NextMethod照原样。

您可以执行以下操作来解决以下事实:所谓的东西都不喜欢被提供foo参数:

`[<-.myClass` <- function(x, i, j, value, foo = FALSE, ...) {
  if (foo) {
    stop("'foo' must be false!")
  }

  `[<-.myClass` <- function(x, i, j, value, ...) NextMethod()
  args <- as.list(match.call())[-1]
  args <- args[names(args) %in% c("","x","i","j","value")]
  do.call("[<-",args)
}

x[1, foo = FALSE] <- 3
x
# [1] 3 2
# attr(,"class")
# [1] "myClass"

另一个示例,其类更复杂:

library(data.table)
x        <- as.data.table(iris[1:2,1:2])
class(x) <- c("myClass",class(x))

x[1, 2, foo = FALSE] <- 9999
#    Sepal.Length Sepal.Width
# 1:          5.1        9999
# 2:          4.9           3

class(x)
# [1] "myClass"    "data.table" "data.frame"

如果下一个方法具有除xijvalue之外的其他参数,则此方法将失败,在这种情况下,最好明确说明我们的其他参数和运行args <- args[! names(args) %in% c("foo","bar")]。然后它可能会起作用(只要参数明确给出为match.call不会捕获默认参数)。我无法对此进行测试,因为我不知道[<-的这种方法。