问题描述
在 R 中,我有一个模拟一维向量的 S3 类,所以我想实现 mean
、sum
、max
等的自定义版本。假设它看起来像像这样:
my_class = function(){
structure(list(),class='my_class')
}
以上所有方法都可以正常工作,如果我定义了 mean.my_class
等:
mean.my_class = function(x){
2
}
mean(my_class())
但是,我也想对 var
之类的函数执行此操作,它不是通用方法。如果我创建这样一个函数,然后在我的类的一个实例上调用 var
:
var.my_class = function(his){
# Do stuff here
}
var(my_class())
我收到错误:
Error in var(my_class()) : is.atomic(x) is not TRUE
这是因为没有通用的 var
函数,它只是在我的结构上调用 stats::var
。如果没有通用方法,我如何提供自定义实现?我也不想破坏常规向量的 var
方法。
解决方法
您可以使用与现有非泛型函数相同的名称和签名创建自己的泛型:
var = function (x,y = NULL,na.rm = FALSE,use) UseMethod('var')
var.my_class = function (x,y,na.rm,use) 42
registerS3method('var','default',stats::var)
registerS3method('var','my_class',var.my_class)
... 而不是手动复制泛型函数的形式参数列表,您可以改为使用以下内容自动生成它:
var = function () UseMethod('var')
formals(var) = formals(stats::var)
——当然,以上只有在调用者调用您的 var
函数时才有效。如果有人调用 stats::var
实例,则不会找到您的泛型,因此不会发生 S3 方法调度。
请注意,R 3.5 改变了 S3 方法查找跨环境的工作方式,仅定义适当命名的函数已不足以从不同的环境中找到该方法 - 您需要调用 registerS3method
(不仅适用于 var
这样的新泛型,还适用于您的 mean
!)。不幸的是,这个函数几乎没有官方文档,只有一些blog posts by Kurt Hornik。
从 methods for non generics 开始,S4
setMethod
似乎与 S3
类兼容:
setMethod("var","my_class",function(x,use) {"Var for my_class"})
#> Creating a generic function for 'var' from package 'stats' in the global environment
#> in method for 'var' with signature '"my_class"': no definition for class "my_class"
my_class = function(){
structure(list(),class='my_class')
}
var(my_class())
#> [1] "Var for my_class"
var(1:10)
#> [1] 9.166667