我实现了一个包含data.table
的S4类,并尝试实现对象的[
子集(如here所述),这样它也会对{ {1}}。例如(仅定义data.table
子集):
i
此时,使用数字向量(library(data.table)
.SuperDataTable <- setClass("SuperDataTable", representation(dt="data.table"))
setMethod("[", c("SuperDataTable", "ANY", "missing", "ANY"),
function(x, i, j, ..., drop=TRUE)
{
initialize(x, dt=x@dt[i])
})
d = data.table(a=1:4, b=rep(c("x", "y"), each=2))
s = new("SuperDataTable", dt=d)
)进行子集化可以根据需要工作(它会对插槽中的s[1:2]
进行子集化)。但是,我想使用表达式添加子集功能。这适用于data.table
本身:
data.table
但不适用于S4 s@dt[b == "x"]
# a b
# 1: 1 x
# 2: 2 x
方法:
[
问题似乎是,使用R的传统惰性评估不会评估S4方法签名中的参数 - 请参阅here:
泛型函数签名中的所有参数都是 在调用函数时评估,而不是使用 S的传统懒惰评价规则因此,它很重要 从签名中排除需要处理的任何参数 象征性地(例如功能替代的第一个参数)。
这解释了为什么它不起作用,而不是 如何实现这种子集化的原因,因为s[b == "x"]
# Error: object 'b' not found
和i
包含在签名中通用的。有没有办法立即评估j
参数而不是?
答案 0 :(得分:1)
你可能对此不太满意。来自R developer notes,
通用函数的签名中出现的参数将立即进行评估 叫做;因此,任何需要利用懒惰评估的论点都不得参与其中 签名。这些通常是字面处理的参数,通常通过substitute()函数处理。 例如,如果有人想将substitute()本身变成泛型,那么第一个参数expr, 不会出现在签名中,因为它不能被评估,而是被视为文字。
此外,由于方法缓存,
如上所述评估完整签名中的所有参数,而不仅仅是活动的 那些。否则,在特殊情况下,函数的行为可能会改变一个 缓存另一种方法时的方法,非常不受欢迎。
我会按照data.table
包编写器中的示例来使用S3对象(参见source code中R/data.table.R
的第304行)。您的S3对象仍然可以创建和操作下面的S4对象,以维护半静态类型功能。
我们不能非常聪明:
‘[’ is a primitive function; methods can be defined, but the generic function is implicit, and cannot be changed.
定义S3和S4方法将调度S3方法,这使得我们应该能够绕过S4调用并手动调度它,但不幸的是,参数评估仍然会发生!你可以通过借用plyr::.
来接近,它会给你如下语法:
s <- new('SuperDataTable', dt = as.data.table(iris))
s[.(Sepal.Length > 4), 2]
不理想,但比其他任何东西都要近。