2

在 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从这条线上删除。当然,有这样的台词是很愚蠢的。更不用说屏幕上的垃圾了。

4

1 回答 1

3

您遇到过惰性求值——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"

大概有无数种强制评估的方法;不过,我认为 usingforce可以使您的意图最清楚。

直接引用帮助文件,

force 强制对形式论证进行评估。如果参数将通过词法作用域规则在闭包中捕获并且稍后将通过循环或应用函数中的显式赋值或隐式赋值进行更改,这将很有用。

随后,

这是语义糖:仅评估符号将做同样的事情(参见示例)。

其实看怎么force定义的,

R> force
#function (x) 
#  x
#<bytecode: 0x3b7b528>
#<environment: namespace:base>

你甚至可以逃脱

ffactory <- function(i) {
  i; function() i
}

但如前所述,我认为显式调用force将使您的代码更具可读性。

于 2015-12-09T00:47:34.417 回答