在 R 中,我想创建一个类 (R6Class),在调用初始化时会创建一些动态方法(方法的数量及其名称取决于初始化中的参数)。但我遇到了奇怪的环境问题。
这是一个不起作用的简化版本的代码。
library(R6)
ffactory <- function(i) {
function() i
}
A <- R6Class(
lock_objects=FALSE,
public=list(
initialize=function(args) {
for (i in args) {
self[[i]] <- ffactory(i)
}
}
)
)
a <- A$new(c('a', 'b', 'c'))
现在:
> a$a()
[1] "c"
> a$b()
[1] "c"
> a$c()
[1] "c"
为了找出问题所在,我添加了一行在 ffactory 函数中打印环境的行。那就是
ffactory <- function(i) {
print(ls.str())
function() i
}
现在它已经开始工作了!!!
> a$a()
[1] "a"
> a$b()
[1] "b"
> a$c()
[1] "c"
那么为什么呢?应该有什么我不明白的地方。观察者效应还是什么? :)
这条线有什么魔力print(ls.str())
?实际上我无法删除 print
也不str
从这条线。当然,有这样的台词是很愚蠢的。更不用说屏幕上的垃圾了。
最佳答案
您遇到过延迟求值的情况 - R 在求值 i
之前会等待尽可能长的时间 - 在前一种情况下,i
将以其最后一个值求值在所有情况下。 print
和 ls.str
的组合并没有什么特别之处;任何强制在方法调用之前评估 i
的内容(a$a()
、a$b()
等... )也会做同样的事情。
正式来说,这就是 force
的用途:
ffactory <- function(i) {
force(i);
function() i
}
R> a$a()
#[1] "a"
R> a$b()
#[1] "b"
R> a$c()
#[1] "c"
但是,这也恰好可以完成这项工作:
ffactory <- function(i) {
#force(i);
.z <- capture.output(cat(i, "\n"))
function() i
}
R> a$a()
#[1] "a"
R> a$b()
#[1] "b"
R> a$c()
#[1] "c"
强制评估的方法大概有无数种;不过,我认为使用 force
可以让你的意图最清楚。
直接引用帮助文件,
force forces the evaluation of a formal argument. This can be useful if the argument will be captured in a closure by the lexical scoping rules and will later be altered by an explicit assignment or an implicit assignment in a loop or an apply function.
随后,
This is semantic sugar: just evaluating the symbol will do the same thing (see the examples).
事实上,看看force
是如何定义的,
R> force
#function (x)
# x
#<bytecode: 0x3b7b528>
#<environment: namespace:base>
你甚至可以逃脱
ffactory <- function(i) {
i; function() i
}
但如上所述,我认为显式调用 force
将使您的代码更具可读性。
关于r - 在 R6Class 中创建动态方法,print(ls.str()) 的魔力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34168116/