R S4方法参数的惰性计算

R S4方法参数的惰性计算,r,oop,data.table,subset,s4,R,Oop,Data.table,Subset,S4,我正在实现一个包含数据.table的S4类,并尝试实现对象的[子集(如上所述),以便它也对数据.table进行子集设置。例如(仅定义I子集): 但不适用于S4[方法: s[b == "x"] # Error: object 'b' not found 问题似乎是S4方法签名中的参数没有使用R的传统惰性评估进行评估-请参阅: 泛型函数签名中的所有参数都将 在调用函数时求值,而不是使用 传统的S的惰性评估规则。因此,重要的是 从签名中排除任何需要处理的参数 象征性地(例如函数替换的第一个参数) 这

我正在实现一个包含
数据.table
的S4类,并尝试实现对象的
[
子集(如上所述),以便它也对
数据.table
进行子集设置。例如(仅定义
I
子集):

但不适用于S4
[
方法:

s[b == "x"]
# Error: object 'b' not found
问题似乎是S4方法签名中的参数没有使用R的传统惰性评估进行评估-请参阅:

泛型函数签名中的所有参数都将 在调用函数时求值,而不是使用 传统的S的惰性评估规则。因此,重要的是 从签名中排除任何需要处理的参数 象征性地(例如函数替换的第一个参数)


这解释了为什么它不起作用,但不是如何实现这种子集,因为
i
j
包含在泛型的签名中。有没有办法不立即计算
i
参数?

你可能在这一点上运气不佳。从

泛型函数的签名中出现的参数将在泛型函数 调用;因此,任何需要利用惰性计算的参数都不能在 签名。这些通常是逐字处理的参数,通常通过substitute()函数处理。 例如,如果要将substitute()本身转换为泛型,则第一个参数expr, 不会出现在签名中,因为不能对其求值,而应将其视为文字

此外,由于方法缓存

完整签名中的所有参数的计算如上所述,而不仅仅是活动签名 否则,在特殊情况下,函数的行为可能会发生改变 方法缓存另一个方法时,显然不需要

我将遵循
data.table
软件包编写器中的示例,使用S3对象(请参见其中
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]
s4),2]

不理想,但比其他任何操作都更接近。

我想我有点困惑。我通常认为初始化步骤是
新建
操作的一部分,而不是提取操作的一部分。@IShouldBuyABoat
初始化的用法来自(也链接到上面),这是因为
初始化
是一个复制构造函数。如果要将其替换为
x@dt = x@dt[i] ;返回(x)
您可以:它与上述问题无关。如果R不知道参数的类别,它怎么知道调用什么方法呢?@hadley:可以想象,如果该参数的签名是
ANY
,因此它不需要知道参数的类别,它就可以工作(虽然我知道它没有)。谢谢你的详细回答-你能详细说明一下“在下面创建和操作S4对象”吗?你的意思是说S3对象有一个S4对象的成员(比如
s$myS4obj
?)我试图让它在S4中工作的主要原因是。@DavidRobinson您可以实现标准S3接口,但可以将S4对象保留在S3对象的列表中,或者将其粘贴在属性中。确保编写
print
方法,以便您的用户看不到内部的深层次。我不确定Bioconductor的封装支架ards,但正如我所说,如果你真的需要一个纯S4对象,你可以使用上面的
()
技巧——正如我的研究所表明的,没有任何其他解决方案可以提供你想要的,而不试着编写会弄乱R内部的C代码。
 ‘[’ is a primitive function;  methods can be defined, but the generic function is implicit, and cannot be changed.
s <- new('SuperDataTable', dt = as.data.table(iris))
s[.(Sepal.Length > 4), 2]