如何为内部泛型的方法添加额外的参数?

How can I add additional arguments to methods for internal generics?

我想为我的 class myClass 实现内部泛型 [<- (~ help(Extract)) 的插入方法。 此方法应该 运行 一堆测试,然后通过 NextMethod().

将实际的 insetting 关闭到 [<-

我明白了:

这是我的代表:

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 没有可作为索引的第二个维度)。

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

我怎样才能避免NextMethod()因为我的方法的额外参数而窒息?

(奖励:有人知道为内部泛型构建方法的好资源吗?@Hadleys adv-r 在这件事上有点短)。


带有显式参数的 Reprex:

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

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

来自?NextMethod

NextMethod invokes the next method (determined by the class vector, either of the object supplied to the generic, or of the first argument to the function containing NextMethod if a method was invoked directly).

您的 class 向量是:

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

所以你这里没有"next method",[<-.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"

另一个例子,更复杂 class :

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 不捕获默认参数)。我无法对此进行测试,因为我不知道 [<-.

的这种方法

除了删除 class(复制 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"

这不是通用方法 - 只有 [[<- 等才需要它,因为它们不使用参数匹配的常规规则:

Note that these operations do not match their index arguments in the standard way: argument names are ignored and positional matching only is used. So m[j = 2, i = 1] is equivalent to m[2, 1] and not to m[1, 2].

(来自 ?`[` 中的 "Argument matching" 部分)

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

无效的方法:

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

  • 取消绑定foorm(foo):这会导致关于未定义foo的错误。

  • 用缺少的符号替换 foo:这会导致错误,即 foo 未提供默认参数。