使用 R 的 data.table 包,
这有效:
instruction = "a = data.table(name=1:3, value=1:3, blah=1:3); a[,c('value', 'blah'):=NULL]"
eval(parse(text=instruction))
# name
#1: 1
#2: 2
#3: 3
这有效:
myFunc = function(instruction) {
eval(parse(text=instruction))
}
myFunc(instruction)
# name
#1: 1
#2: 2
#3: 3
现在,将此函数放入包中,加载它,然后尝试调用它。这不起作用:
myFuncInPackage(instruction)
#Error in `:=`(c("value", "blah"), NULL) :
# Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").
为什么?
编辑:@Roland指出,在包Depends
字段中添加data.table可以使其工作。但是,我认为这不是一个很好的解决方案,因为该包并不真正依赖、要求或使用 data.table。我只是希望能够在包中使用data.table。
此外,data.table 的其他所有内容在函数中都可以正常工作,只是:=
运算符无法正常工作。
所以我想一个后续问题可能是:我是否应该将 data.table 添加到我编写的每个包的依赖项中,以便 data.tables 在该包的函数中按预期工作?这似乎不对...解决这个问题的正确方法是什么?
我遇到了同样的问题,我解决了它,将data.table
添加到Imports
和Depends:
。我的data.table
版本是1.9.6
我终于找到了这个问题的答案(几年后)。所有评论和答案都建议在Depends
或Imports
中添加data.table
,但这是不正确的;包不依赖于data.table
,这可能是假设的任何包,而不仅仅是data.table,这意味着从逻辑上得出结论,建议需要将所有可能的包添加到Depends
- 因为该依赖项由提供instruction
的用户提供,而不是由包提供的函数提供。
相反,基本上,这是因为对eval
的调用是在包的命名空间内完成的,这不包括其他包提供的函数。我最终通过在eval
调用中指定全局环境来解决此问题:
myFunc = function(instruction) {
eval(parse(text=instruction), envir=globalenv())
}
为什么有效
这会导致在搜索路径中包含必要包的环境中完成eval
功能。
在data.table
情况下,由于函数重载的复杂性,调试起来特别困难。在这种情况下,罪魁祸首实际上不是:=
函数,而是[
函数。:=
错误是红鲱鱼。在撰写本文时,data.table
中的:=
函数定义如下:
https://github.com/Rdatatable/data.table/blob/348c0c7fdb4987aa6da99fc989431d8837877ce4/R/data.table.R#L2561
":=" <- function(...) stop('Check that is.data.table(DT) == TRUE. Otherwise, := and `:=`(...) are defined for use in j, once only and in particular ways. See help(":=").')
就是这样。这意味着:任何对:=
作为函数的调用都会停止并显示错误消息,因为这不是作者打算:=
使用的方式。相反,:=
实际上只是由 data.table
中的 [
函数解释的关键字。
但是这里会发生什么:如果[
函数没有正确映射到 data.table
指定的版本,而是映射到基本[
,那么我们就遇到了问题——因为它无法处理:=
,因此它被视为函数并触发错误消息。所以罪魁祸首函数是[.data.table
-- 重载括号运算符。
正在发生的事情是在我的新包(包含myFuncInPackage
),当它去计算代码时,它会将[
函数解析为基[
函数,而不是data.table
的[
函数。它尝试将:=
评估为函数,[
不会使用它,因为它不是正确的[
,因此:=
作为函数而不是作为值传递给data.table
的,因为data.table
不在命名空间中(或在search()
层次结构中较低。在此设置中,:=
不被理解,因此将其作为函数进行评估,从而触发上述data.table
代码中的错误消息。
当您指定在全局环境中发生的 eval 时,它会正确地将 [
函数解析为 [.data.table
,并且正确解释:=
。
顺便说一下,如果你传递的不是字符串,而是代码块(更好)来eval()
包中,你也可以使用它:
eval(substitute(instruction), envir=globalenv())
在这里,substitute
防止instruction
在 argument-eval 阶段在包命名空间中被解析(错误),以便它完整地返回到 globalenv,在那里可以使用所需的函数正确评估它。