在 R6Class 中创建动态方法,print(ls.str()) 的魔力
Creating dynamically methods in R6Class, magic of print(ls.str())
在 R 中,我想创建一个 class (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
的组合并没有什么特别之处;在您的方法调用(a$a()
、a$b()
等)之前强制评估 i
的任何内容都会执行相同的操作。
形式上,这就是 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 中,我想创建一个 class (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
的组合并没有什么特别之处;在您的方法调用(a$a()
、a$b()
等)之前强制评估 i
的任何内容都会执行相同的操作。
形式上,这就是 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
将使您的代码更具可读性。