使用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添加到我编写的每个包的Depends中,以便data.tables在该包的函数中按预期工作吗?这似乎不正确......解决这个问题的正确方法是什么?
答案 0 :(得分:5)
我遇到了同样的问题,我解决了将data.table
添加到Imports
和Depends:
的问题。我的data.table
版本为1.9.6
答案 1 :(得分:1)
我终于找到了这个问题的答案(几年后)。所有评论和回答建议将data.table
添加到Depends
或Imports
,但这是不正确的;该包不依赖于data.table
,并且可能是假设的任何包,而不仅仅是data.table,意味着得出逻辑结论,该建议需要将所有可能的包添加到Depends
- 因为依赖性由提供instruction
的用户提供,而不是由包提供的功能提供。
相反,基本上,它是因为对eval
的调用是在包的命名空间内完成的,并且这不包括其他包提供的功能。我最终通过在eval
调用中指定全局环境来解决这个问题:
myFunc = function(instruction) {
eval(parse(text=instruction), envir=globalenv())
}
为什么会这样?
这会导致eval
函数在包含搜索路径中必需包的环境中完成。
在data.table
情况下,由于函数重载的复杂性,它特别难以调试。在这种情况下,罪魁祸首实际上不是:=
函数,而是[
函数。 :=
错误是一个红色的鲱鱼。在撰写本文时,:=
中的data.table
函数定义如下:
":=" <- 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
的{{1}}功能。它会尝试将[
评估为:=
未使用的函数,因为它不是正确的[
,因此[
将被传递为函数而不是:=
的值,因为data.table
不在命名空间中(或在data.table
层次结构中较低。在此设置中,{{1不被理解,因此它被评估为一个函数,从而在上面的search()
代码中触发错误消息。
当您指定在全局环境中发生的eval时,它会正确地将:=
函数解析为data.table
,并正确解释[
。
顺便提一下,如果您在包中传递的不是字符串,而是代码块(更好)传递给[.data.table
,也可以使用此功能:
:=
这里,eval()
阻止eval(substitute(instruction), envir=globalenv())
在参数-eval阶段的包命名空间内被解析(错误),这样它就可以完整地回到globalenv,在那里可以正确地评估substitute
具备所需的功能。