我正在实现一个包含 data.table
的 S4 类,并尝试实现对象的 [
子集(如 here 所述),以便它也子集 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
本身:s@dt[b == "x"]
# a b
# 1: 1 x
# 2: 2 x
但不适用于 S4
[
方法:s[b == "x"]
# Error: object 'b' not found
问题似乎是 S4 方法签名中的参数没有使用 R 的传统惰性求值进行求值 - 请参阅 here :
这解释了为什么它不起作用,但不能解释如何实现这种子集,因为
i
和 j
包含在泛型的签名中。有没有办法不立即评估 i
参数? 最佳答案
你可能在这方面不走运。从 R developer notes ,
此外,由于方法缓存,
我将遵循 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]
不理想,但比其他任何东西都更接近。
关于r - S4 方法参数的惰性求值,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/22593102/