R语言 如何重载S4插槽选择器`@`成为泛型函数

jhiyze9q  于 2023-04-03  发布在  其他
关注(0)|答案(2)|浏览(173)

我正在尝试将R中的@操作符转换为S3系统的通用函数。
基于编写R扩展中的章节:添加新的泛型我试着实现@的泛型如下:

`@` <- function(object, name) UseMethod("@")
`@.default` <- function(object, name) base::`@`(object, name)

然而,这似乎不起作用,因为它破坏了S4方法的@。我使用Matrix包作为S4示例的示例:

Matrix::Matrix(1:4, nrow=2, ncol=2)@Dim

@.default(Matrix::Matrix(1:4,nrow = 2,ncol = 2),Dim)中的错误:类“dgeMatrix”的此对象没有名称为“name”的插槽
如何实现泛型@,以便在S4类的情况下正确调度?

编辑

也对为什么这可能不是一个好主意的意见感兴趣?

yzckvree

yzckvree1#

R的文档对于@是否已经是泛型有点混乱:@的帮助页面说它是,但它没有列在internalGenerics页面上。
@操作符有特定的行为,也可能是一个泛型。从@的帮助页面:“检查对象是否是S4对象(参见isS 4),尝试在任何其他对象上使用@是错误的。”这似乎排除了为S3类编写方法的可能性,尽管文档不清楚这种检查是发生在方法分派之前(如果有的话)还是之后(如果您为某些S3类提供了特定的方法,则可以跳过它)。
你可以通过完全重新定义@来实现你想要的东西,沿着评论中的建议:

`@.default` <- function(e1,e2) slot(e1,substitute(e2))

但有两个理由不这样做:
1)一旦有人加载了你的包,它就会取代普通的@函数,所以如果人们用其他S4对象调用它,他们得到的是你的版本,而不是R的基础版本。
2)这个版本比内部版本的效率要低得多,因为(1)你只是强迫你的用户使用它(除非他们使用麻烦的结构base::"@"(e1,e2))。效率可能对你的用例无关紧要,但它可能对你的用户使用S4的其他代码很重要。
实际上,一个合理的折衷方案可能是定义自己的二元运算符%@%,并使用默认方法调用@

`%@%` <- function(e1,e2) slot(e1,substitute(e2))
setGeneric("%@%")

这在实践中称为:

> setClass("testClass",slots=c(a="character")) -> testClass
> x <- testClass(a="cheese")
> x %@% a
[1] "cheese"
nqwrtyyt

nqwrtyyt2#

在R 4.3.0及更新版本中,@运算符将在内部是S3泛型的,如最新的NEWS中所述:
@运算符现在是一个S3泛型。基于Tomasz Kalinowski在PR#18482中的贡献。
如果你不想等待4月21日发布的R 4.3.0,你可以在R-devel上进行测试:

.S3method("@", "zzz", function(object, name) "OK")
structure(0, class = "zzz")@whatever
## [1] "OK"

相关问题