这只是我正在编写的更复杂代码的MWE。
假设我想创建一个新方法newMethod
,它(除其他外)需要从数据帧data
中提取变量x
,但也需要从data
中提取一些附加属性(例如,它的列名)。
我首先将S3泛型定义如下
newMethod <- function(x, data) UseMethod("newMethod")
为了从data
中提取x
,我编写了newMethod.default
:
newMethod.default <- function(x, data) {
x <- eval(substitute(x), envir = data)
return(list(x = x, names = names(data)))
}
根据class(x)
,我计划进行进一步的调度(可能在返回列表之前,在newMethod.default
内部),但这在这里并不重要(我只是在这里提到它,以解释为什么我首先要创建一个泛型函数)。
然而,当我通过运行来测试这个通用
newMethod(mpg, mtcars)
我收到(也许并不奇怪)错误消息:Error in newMethod(mpg, mtcars) : object 'mpg' not found
。所以现在我想知道什么是最好的解决办法。我的直觉是将部分代码从newMethod.default
移动到newMethod
,就像我在这里做一样
newMethod <- function(x, data) {
x <- eval(substitute(x), envir = data)
UseMethod("newMethod", x)
}
但我不太确定这是常见的还是好的做法,部分原因是建议不要使用UseMethod
的第二个自变量。此外,我需要保持newMethod.default
的第一行不变,否则我将再次收到错误消息。
如果有人能为我指明正确的方向,我将不胜感激,因为我觉得我在这件事上不太对劲。非常感谢!
发生这种情况的原因与方法无关,只与R读取代码的方式有关。它查看了第一个参数,并决定在此基础上进行一些调度。但问题是这个对象mpg
不存在,所以R没有办法决定应该调用什么方法。R需要能够确定该对象的类。"不存在"不是一个类,因此不可能对调用函数的环境中不存在的对象进行调度。
看看with()
函数和缺省方法with.default()
。这基本上就是你在这里所做的,但有点笼统。它的默认方法实际上与您的示例几乎完全相同:
> with.default
function (data, expr, ...)
eval(substitute(expr), data, enclos = parent.frame())
<bytecode: 0x0825d7d8>
<environment: namespace:base>
重要的部分是with()
将数据参数作为第一个参数,将表达式(在您的情况下,仅为mpg
)作为第二个参数。这样一来,调用帧中不存在mpg
就无关紧要了,因为R在尝试调度时只查看第一个参数。
所以这是有效的:
newMethod <- function( data, x) UseMethod("newMethod")
newMethod.default <- function(data, x) {
x <- eval(substitute(x), envir = data)
return(list(x = x, names = names(data)))
}
附带说明:再次考虑newMethod.default
内部的调度。不确定你到底想实现什么,但我觉得这是你使用NextMethod
的目的。但这是一个棘手的问题,在这种情况下,转移到S4可能会方便得多,原因很简单,你可以对类的组合使用S4方法,甚至对缺少的参数使用S4方法。但是,只要您停留在S3中,就没有办法捕获不存在的对象,除了在泛型函数中使用exists()
之外,例如:
newMethod <- function( data, x) {
if(exists(deparse(substitute(x))))
UseMethod("newMethod")}
但这是我自己不会使用的代码。