问题
I've defined a list of anonymous functions which use a variable defined in an outer scope.
funclist <- list()
for(i in 1:5)
{
funclist[[i]] <- function(x) print(i)
}
funclist[[1]]('foo')
The output is:
[1] 5
It seems that i is captured by reference. I'd like it to be captured by value, i.e. the output should be
[1] 1
Is there a way to tell R to capture i by value rather than by reference?
回答1:
When you run a for
loop, this creates a variable in the environment the loop is run in, and functions created in the loop are also run from this environment. So whenever you run the functions created in this way that use the index value from the loop, they only have access to the final value, and only as long as that varaible remains (try rm(i)
and attempting to fun one of the functions in the list).
What you need to do is bind the index value to the function in their own environment. lapply
will do this for you automatically. However, there is a gotcha with lazy evaluation. What you have to do is also force
the evaluation of i
before creating the anonymous function:
funclist <- lapply(1:5, function(i) {force(i); function(x) print(i)})
funclist[[1]]('foo')
[1] 1
funclist[[5]]('foo')
[1] 5
回答2:
My read on what you want is to store a value inside the function's environment when the function is defined, and then hold onto that value for internal computations.
For that, you want a closure:
i <- 3
test <- local({
i <- i
function(x) x[i]
})
test(letters[1:5]) # returns 'c'
i <- 5
test(letters[1:5]) # still returns 'c' (i.e. i is local to the test closure)
Is that what you wanted?
来源:https://stackoverflow.com/questions/16216909/r-anonymous-function-capture-variables-by-value