一般作用域
这与作用域有关.在抛出错误的情况下,调用错误处理程序function,如果它们与全局环境中的变量具有相同的名称,则调用错误处理程序function,其跟踪其自身的变量even.下面的例子说明了这一 idea :
a <- 1
f <- function() {
cat("Before a is defined in the function it takes the value from global:", a, "\n")
a <- 2
cat("After a is defined in the function it takes the value from local:", a, "\n")
}
f()
# Before a is defined in the function it takes the value from global: 1
# After a is defined in the function it takes the value from local: 2
cat("After the function is called we only see the global scope:", a, "\n")
# After the function is called we only see the global scope: 1
您可以在全局环境中使用<<-
为函数赋值,但通常最好避免这种模式:
a <- 1
g <- function() {
a <<- 2
}
print(a)
# [1] 1
g() ## changes a on global scope
print(a)
# [1] 2
try 捕捉
在try 捕捉
以内,同样的 idea 也适用.主代码在global范围内求值(也就是说,我们可以在global范围内修改变量,而不需要<<-
),但在错误处理程序(实际上是function)中,我们需要使用<<-
对全局sope进行赋值:
even <- list()
even2 <- list()
odd <- list()
odd_bad <- list()
for (i in 1:2) {
for (j in 1:3) {
try 捕捉({
stopifnot("i * j must be even" = i * j %% 2 == 0)
## works because this code is evaluated on global scope
even2 <- c(even2, list(c(i, j)))
even <<- c(even, list(c(i, j)))
}, error = function(err) {
## does not work creates a local version of odd_bad which is later discarded
odd_bad <- c(odd_bad, list(c(i, j)))
odd <<- c(odd, list(c(i, j)))
})
}
}
length(even)
# [1] 2
length(even2)
# [1] 2
length(odd)
# [1] 4
length(odd_bad)
# [1] 0
避免全局赋值的更好模式
因为在全局范围内通过<<-
赋值变量应该谨慎使用,所以更好的解决方案是从主代码和错误处理程序中返回一个元素,并使用一个标志(例如类)进行修改,然后我们可以使用它轻松地过滤好的和坏的结果.这完全避免了全局赋值:
res <- list()
for (i in 1:2) {
for (j in 1:3) {
res <- c(res,
try 捕捉({
stopifnot("i * j must be even" = i * j %% 2 == 0)
list(structure(list(c(i, j)), class = "good"))
}, error = function(err) {
list(structure(list(c(i, j)), class = "bad"))
})
)
}
}
Filter(\(e) inherits(e, "good"), res) ## all good results
Filter(\(e) inherits(e, "bad"), res) ## all badd results