如何在循环中向R中的R6Class添加函数

时间:2019-05-17 15:34:54

标签: r r6

我想为R6Class编写包装器,但是它不起作用,发现这个问题dynamically add function to r6 class instance

后,我尝试了多种方法

所以我已经尝试过了,但是它们都不起作用:

get <- function(x = list()) {
  class <- R6::R6Class(classname = "class")
  for (name in names(x)) {
    class$set("public", name, function() name)
  }
  class
}

x <- get(x = list(a = 10, b = 20))$new()
x$a()
# b
x$b()
# b

这是因为for的闭包循环不会创建新的作用域。所以我尝试了这个:

get <- function(x = list()) {
  class <- R6::R6Class(classname = "class")
  lapply(names(x), function(name) {
    print(name)
    class$set("public", name, function() name)
  })
  class
}

x <- get(x = list(a = 10, b = 10))$new()
x$a()

这将引发未定义名称的错误,因为R6Class的这种行为是所有内容都在eval substitute中,所以没有办法使新函数从调用它的地方获取作用域/环境。还是有办法?

我的真正问题是我想创建函数包装器并调用:

fn <- function() {
    x <- 10
    y <- myFunction(public = list(
       foo = function(y) {
          x + y
       }
    })
    z <- y$new()
    z$foo(10)
    ## I want 20 as result
}

有没有一种方法来创建将创建R6Class的myFunction函数?之所以这样,是因为我有基于R6Class的组件系统,并且想要删除一些需要添加到每个类中的样板,因此更易于使用。我不想创建新的类系统,我想使用R6类。

1 个答案:

答案 0 :(得分:1)

添加此问题后,我在GitHub上提问,他们很快给出了答案。这是答案的重新发布:

In [11]: a = 1                                                                                                                                                                                                               

In [12]: a = 1L                                                                                                                                                                                                              
  File "<ipython-input-12-61aa3f5b6495>", line 1
    a = 1L
         ^
SyntaxError: invalid syntax

如果在打印x $ a时想要更好的名称,则可以使用以下命令清除名称ref:

get <- function(x = list()) {
  class <- R6::R6Class(classname = "class")
  lapply(names(x), function(name) {
    fn <- eval(substitute(function() subst_name, list(subst_name = name)))
    class$set("public", name, fn)
  })
  class
}
x <- get(x = list(a = 10, b = 20))$new()
x$a()

编辑

这是添加到类的值是函数的示例(这是我改进的代码):

attr(fn, "srcref") <- NULL

,如果您想访问超级帐户,则需要使用以下代码:

EDIT2

constructor <- function(public = list(), private = list()) {
  class <- R6::R6Class(classname = "class")
  lapply(names(public), function(name) {
    if (is.function(public[[name]])) {
      env <- environment(public[[name]])
      env$self <- public
      env$private <- private
      fn <- eval(substitute(function(...) fn(...), list(fn = public[[name]])))
      class$set("public", name, fn)
    } else {
      class$set("public", name, public[[name]])
    }
  })
  class
}
test <- function() {
  a <- 10
  class <- constructor(
     public = list(
         a = function() { a + self$b },
         b = 20
     )
  )
  x <- class$new()
  x$a()
}

test()

除了component <- function(public = NULL, private = NULL, static = NULL, ...) { class <- R6::R6Class(...) r6.class.add(class, public) r6.class.add(class, private) class$extend <- make.extend(class) class } #' helper function for adding properties to R6Class r6.class.add <- function(class, seq) { prop.name <- as.character(substitute(seq)) # so we don't need to write name as string lapply(names(seq), function(name) { if (is.function(seq[[name]])) { ## the only way to have scope from when function was create with self and private ## eval substitute simply circument R6 encapsulation and use scope from where function ## was created (closure) and env.fn patch the env of inner function so it get self ## and private as magic names - this is done so component function the same as ## when R6Class is created inline - so component is referencial transparent and can ## be replaced with R6Class fn <- eval(substitute(function(...) { ## patch function env fn <- fn.expr # fn.expr will be inline function expression parent <- parent.env(environment()) ## we don't overwrite function scope so you can nest one constructor ## in another constructor env <- new.env(parent = environment(fn)) env$self <- parent$self env$super <- parent$super env$private <- parent$private environment(fn) <- env fn(...) }, list(fn.expr = seq[[name]], name = name))) class$set(prop.name, name, fn) } else { class$set(prop.name, name, seq[[name]]) } }) } 之外,您还可以使用env$self <- parent$self(它将在环境链中搜索变量)。