如何在循环中将函数添加到 R 中的 R6Class
How to add functions in a loop to R6Class in R
我想在 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
这是因为闭包循环不会创建新的作用域。所以我试过这个:
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
中,因此无法创建从其所在位置获取 scope/environment 的新函数被称为。或者有什么办法吗?
我真正的问题是我想创建函数包装器并且我想调用:
fn <- function() {
x <- 10
y <- myFunction(public = list(
foo = function(y) {
x + y
}
})
z <- y$new()
z$foo(10)
## I want 20 as result
}
有没有办法创建 myFunction
函数来创建 R6Class?我想要这个的原因是因为我有基于 R6Class 的组件系统,并且想删除一些需要添加到每个 class 的样板,这样它更容易使用。我不想创建新的 class 系统,我想使用 R6 classes.
我在添加这个问题后在 GitHub 上提问,他们很快就给出了答案。这是 re-post 的答案:
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()
如果你想在打印 x$a 时使用更好的名称,你可以使用以下方法清除名称引用:
attr(fn, "srcref") <- NULL
编辑:
这是添加到 class 的值是函数的示例(这是我改进的代码):
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()
如果您想访问 super,您需要使用此代码:
EDIT2:
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]])
}
})
}
您也可以使用 get("self", parent)
而不是 env$self <- parent$self
(它将在环境链中搜索变量)。
我想在 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
这是因为闭包循环不会创建新的作用域。所以我试过这个:
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
中,因此无法创建从其所在位置获取 scope/environment 的新函数被称为。或者有什么办法吗?
我真正的问题是我想创建函数包装器并且我想调用:
fn <- function() {
x <- 10
y <- myFunction(public = list(
foo = function(y) {
x + y
}
})
z <- y$new()
z$foo(10)
## I want 20 as result
}
有没有办法创建 myFunction
函数来创建 R6Class?我想要这个的原因是因为我有基于 R6Class 的组件系统,并且想删除一些需要添加到每个 class 的样板,这样它更容易使用。我不想创建新的 class 系统,我想使用 R6 classes.
我在添加这个问题后在 GitHub 上提问,他们很快就给出了答案。这是 re-post 的答案:
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()
如果你想在打印 x$a 时使用更好的名称,你可以使用以下方法清除名称引用:
attr(fn, "srcref") <- NULL
编辑:
这是添加到 class 的值是函数的示例(这是我改进的代码):
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()
如果您想访问 super,您需要使用此代码:
EDIT2:
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]])
}
})
}
您也可以使用 get("self", parent)
而不是 env$self <- parent$self
(它将在环境链中搜索变量)。