如何查看R中被修改的环境?解析状态函数的变量存储
R词法作用域实现有状态函数的机制解析
背景示例
有人用R的词法作用域实现了一个模拟类的有状态函数,代码如下:
point <- function(x, y){ structure(class = "point", list( x = x, y = y, get_x = function() paste("(", x,",",y,")"), set_x = function(x, y){ x <<- x y <<- y } )) } # 全局变量 x <- 0 y <- 1 # 创建实例 p <- point(0,1) p$get_x() #[1] "( 0 , 1 )" # 修改坐标 p$set_x(6,5) p$get_x() #[1] "( 6 , 5 )" # 全局变量未被修改 x #[1] 0 y #[1] 1
但直接查看实例p时,会发现列表里的x和y还是初始值:
> p $x [1] 0 $y [1] 1 $get_x function() paste('(', x,',',y,')') <environment: 0x557c984f9a48> $set_x function(x, y){ x <<- x y <<- y } <environment: 0x557c984f9a48> attr(,"class") [1] "point"
针对这个现象,以下是关键问题的解析:
核心疑问解答
1. 该机制如何运作?
这是**闭包(Closure)**的典型应用:当point函数被调用时,会创建一个局部执行环境,里面存放着参数x和y的初始值。随后定义的get_x和set_x函数会"捕获"这个局部环境,将其作为自己的父环境。
get_x执行时,会从父环境(即point的执行环境)中读取x和y的值;set_x里的<<-赋值运算符,会向上遍历作用域,找到最近的父环境(也就是point的执行环境),并修改其中的x和y,不会修改全局变量或列表里的x、y。
2. R修改的是本地定义的x、y还是传入的参数?
修改的是**point函数执行时在局部环境中创建的x和y**,既不是传入的参数,也不是全局变量:
- 传入的参数只是用来初始化这个局部环境的变量,
point执行完成后参数就不再被引用; - 全局的
x、y最终未被修改,也证明了<<-没有作用在全局作用域。
3. 被修改的类变量存储在何处?
被修改的x和y存储在get_x和set_x的闭包环境中,也就是point函数执行时生成的专属环境(对应输出里的<environment: 0x557c984f9a48>)。
需要注意:p列表里的x和y只是初始值的副本,和闭包环境里的变量是完全独立的对象,所以直接查看p$x、p$y看不到修改后的值。
4. 能否在R中查看该变量?
可以,通过访问函数的闭包环境就能查看:
# 获取get_x函数的闭包环境 env <- environment(p$get_x) # 查看环境中的x和y env$x #[1] 6 env$y #[1] 5
get_x和set_x共享同一个闭包环境,所以用environment(p$set_x)也能获取到这个环境。
内容的提问来源于stack exchange,提问作者Hasse1987
相关产品推荐
相关产品推荐

