Kon*_*lph 5 r r-s3 non-standard-evaluation
\n\ntl;dr:
\nR CMD check
当我为 S3 类实现泛型时会抱怨<-
,因为它认为该函数是参数不正确的替换函数。
我需要定义一组 S3 泛型来遍历未计算的 R 表达式的 AST。
\n出于演示目的,请考虑以下 S3 泛型及其方法:
\nwalk = function (x) UseMethod(\'walk\')\n\nwalk.default = function (x) message(\'default\')\n\nwalk.name = function (x) message(\'name\')\n\nwalk.call = function (x) message(\'call\')\n
Run Code Online (Sandbox Code Playgroud)\n这工作正常:
\ntests = alist(\'2\', c, f(1))\n\ninvisible(lapply(tests, walk))\n
Run Code Online (Sandbox Code Playgroud)\nwalk = function (x) UseMethod(\'walk\')\n\nwalk.default = function (x) message(\'default\')\n\nwalk.name = function (x) message(\'name\')\n\nwalk.call = function (x) message(\'call\')\n
Run Code Online (Sandbox Code Playgroud)\n然而,有相当多的调用表达式的 S3 类是 \xe2\x80\x99t call
;例如:
tests2 = alist(for (x in y) ., if (.) ., x <- .)\ninvisible(lapply(tests2, walk))\n
Run Code Online (Sandbox Code Playgroud)\ntests = alist(\'2\', c, f(1))\n\ninvisible(lapply(tests, walk))\n
Run Code Online (Sandbox Code Playgroud)\n\xe2\x80\xa6 哎呀。我希望这些表达式被视为调用。我可以通过添加更多方法来做到这一点:
\nwalk.for = function (x) message(\'for\')\n\nwalk.if = function (x) message(\'if\')\n\n`walk.<-` = function (x) message(\'<-\')\n\n# \xe2\x80\xa6 and so on for other syntax constructs.\n
Run Code Online (Sandbox Code Playgroud)\n现在我\xe2\x80\x99m 在调用时得到了预期的结果walk
:
default\nname\ncall\n
Run Code Online (Sandbox Code Playgroud)\n然而,这段代码是包的一部分,并且R CMD check
抱怨 的定义,walk.<-
因为它认为该函数是一个替换函数:
\n\nRun Code Online (Sandbox Code Playgroud)\nW checking replacement functions ...\n \xe2\x80\x98walk.<-\xe2\x80\x99\n The argument of a replacement function which corresponds to the right\n hand side must be named \xe2\x80\x98value\xe2\x80\x99.\n
我明白为什么我\xe2\x80\x99m 收到警告(事实上,这看起来像是为 定义替换函数的拙劣尝试walk.
)。但当然这不是\xe2\x80\x99t替换函数,因此警告是误报。那么我应该如何<-
明确地为该类实现 S3 泛型呢?或者这是一个错误R CMD check
?我可以摆脱警告吗?我可以\xe2\x80\x99t 向函数添加其他参数。
编写 R 扩展,第1.5.2 节注册 S3 方法提供了一个解决方案:
\n\n\n可以指定第三个参数
\nS3method
,即用作方法的函数,例如Run Code Online (Sandbox Code Playgroud)\nS3method(print, check_so_symbols, .print.via.format)\n
什么时候
\nprint.check_so_symbols
不需要。
这意味着我们不定义`walk.<-`
,而是执行以下操作:
R/\xe2\x80\xb9some-file\xe2\x80\xba.r
:walk_assign = function (x) message(\'<-\')\n
Run Code Online (Sandbox Code Playgroud)\n(与其他 S3 方法不同,函数名称并不重要。)
\nNAMESPACE
宣言:S3method(walk, \'<-\', walk_assign)\n
Run Code Online (Sandbox Code Playgroud)\n.S3method(\'walk\', \'<-\', \\(x) message(\'<-\'))
这实际上与在常规 R 脚本内调用相同。有趣的是,似乎.S3method()
也可以在包内工作(而不是基于上述的NAMESPACE
解决方案),但 function\xe2\x80\x99s 文档表示不要在包中使用它,因此将来可能会中断。
当然,正如艾伦·卡梅伦(Allan Cameron)评论的那样,一个可以说更简单的解决方案是将外壳<-
与内部融合default
并使用if
内部walk.default
来消除歧义:
walk.default = function (x) {\n if (inherits(x, \'<-\')) {\n message(\'<-\')\n } else {\n message(\'default\')\n }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n然而,我个人不喜欢将 S3 调度与if
.