R 中的环境是什么
将环境理解为带有父级指针的命名列表
R 中的环境是什么 是 CoddyKit 上的免费 R Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。
什么是环境
在 R 中,环境是由命名绑定组成的集合(类似于命名列表),并带有一个指向父环境的指针。每个变量都存在于某个环境中。当 R 查找名称时,会先搜索当前环境,然后沿父环境链向上查找。
# The global environment holds your session variables
x <- 42
cat('x is in globalenv:', exists('x', envir = globalenv()), '\n')
cat('globalenv name:', environmentName(globalenv()), '\n')globalenv()、baseenv() 和 emptyenv()
R 有多个内置环境:globalenv() 是您的交互式工作区,baseenv() 存放 R 的基础函数,而 emptyenv() 是没有父环境的链顶端。每条环境链最终都会在 emptyenv() 处终止。
cat('global :', environmentName(globalenv()), '\n')
cat('base :', environmentName(baseenv()), '\n')
cat('empty :', environmentName(emptyenv()), '\n')
cat('parent of global:', environmentName(parent.env(globalenv())), '\n')环境链
每个环境恰好有一个父环境(emptyenv() 除外)。当 R 在当前环境中找不到某个名称时,就会移动到父环境,再移动到父环境的父环境,以此类推。这条链决定了 R 如何解析变量名。
# Walk the parent chain from globalenv
env <- globalenv()
for (i in 1:5) {
cat(sprintf('Level %d: %s\n', i, environmentName(env)))
if (identical(env, emptyenv())) break
env <- parent.env(env)
}用于函数的 environment()
每个函数都有一个关联的环境,即创建该函数时所在的环境。environment(f) 会返回该环境。这就是函数的封闭环境,决定了它在哪里查找自由变量。
f <- function() 'hello'
cat('f was defined in:', environmentName(environment(f)), '\n')
# Inside a function, environment() returns its own env
show_env <- function() {
cat('my env:', environmentName(environment()), '\n')
}
show_env()对环境使用 as.list()
as.list(env) 会将环境中的绑定转换为命名列表,这对于以编程方式检查环境内容很有用。将它与 globalenv() 结合使用,可以显示当前会话中的所有变量。
a <- 10
b <- 'hello'
c_val <- TRUE
# Show current global bindings as list
bindings <- as.list(globalenv())
cat('Names in globalenv:', paste(ls(globalenv()), collapse = ', '), '\n')ls()——列出环境内容
ls() 会列出环境中绑定的名称。默认情况下,它显示全局环境中的名称。传入 envir = e 可以检查特定环境。添加 all.names = TRUE 可以包含以 . 开头的名称。
my_env <- new.env(parent = emptyenv())
my_env$x <- 1
my_env$y <- 'two'
my_env$.hidden <- TRUE
cat('Default ls:', ls(envir = my_env), '\n')
cat('All names :', ls(envir = my_env, all.names = TRUE), '\n')new.env() — 创建环境
new.env(parent = e) 会创建一个以给定环境为父环境的全新空环境。如果您需要一个完全隔离、没有任何继承绑定的环境,请使用 emptyenv() 作为父环境。
e <- new.env(parent = emptyenv())
e$name <- 'Alice'
e$score <- 95
cat('Names:', ls(e), '\n')
cat('Name binding:', e$name, '\n')环境与列表
环境看起来像带名称的列表,但行为不同:环境始终会原地修改(不会在修改时复制),具有父环境,并且通过哈希表进行名称查找(速度很快)。列表在修改时会被复制,而环境不会。
# Environments are reference objects (no copy-on-modify)
e <- new.env(parent = emptyenv())
e$x <- 1
f <- e # f points to same env, not a copy
f$x <- 99
cat('e$x after modifying through f:', e$x, '\n')环境中的 exists() 和 get()
exists('name', envir = e) 会检查某个名称是否在环境中绑定(默认也会检查其父环境)。get('name', envir = e) 会获取该值。两者都接受 inherits = FALSE,从而只在指定的环境中查找。
e <- new.env(parent = emptyenv())
e$pi_approx <- 3.14159
cat('exists pi_approx:', exists('pi_approx', envir = e), '\n')
cat('exists missing: ', exists('missing_var', envir = e), '\n')
cat('get pi_approx: ', get('pi_approx', envir = e), '\n')用于内置环境的 environmentName()
environmentName(env) 会返回特殊环境的易读名称。用户创建的环境会返回 ''(空字符串)。调试时,这有助于您追踪变量的定义位置。
cat(environmentName(globalenv()), '\n') # R_GlobalEnv
cat(environmentName(baseenv()), '\n') # package:base
cat(environmentName(emptyenv()), '\n') # R_EmptyEnv
e <- new.env(parent = emptyenv())
cat('User env name: "', environmentName(e), '"\n', sep = '')实践:将环境用作缓存
由于环境会原地修改,因此很适合用作可变缓存或哈希映射。将计算结果存储在环境中可以避免重复计算——这比修改列表更快,因为修改列表会产生复制。
cache <- new.env(parent = emptyenv(), hash = TRUE)
cached_square <- function(n) {
key <- as.character(n)
if (exists(key, envir = cache, inherits = FALSE))
return(get(key, envir = cache))
result <- n^2
assign(key, result, envir = cache)
result
}
cat(cached_square(7), '\n')
cat(cached_square(7), '\n') # served from cache快速检查
R 的环境链中最顶层的环境是哪一个——也就是没有父环境的环境?
环境:要点总结
关于 R 环境的要点:
- 环境 = 命名绑定 + 父环境指针
globalenv()= 您的工作区;baseenv()= R 基础环境;emptyenv()= 环境链终点- 名称查找会沿父环境链向上进行,直到找到名称或到达
emptyenv() ls(envir=e)列出绑定;exists()检查绑定;get()获取值- 环境是引用对象——修改时不会复制
new.env(parent=emptyenv())会创建一个隔离环境
e <- new.env(parent = emptyenv())
assign('counter', 0L, envir = e)
for (i in 1:5) assign('counter', e$counter + 1L, envir = e)
cat('Counter:', e$counter, '\n')
cat('Env name:', environmentName(e), '\n')
cat('Bindings:', ls(e), '\n')常见问题解答
「R 中的环境是什么」课时是免费的吗?
是的 — 「R 中的环境是什么」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。
「R 中的环境是什么」这节课中我会学到什么?
将环境理解为带有父级指针的命名列表 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 R Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。
「R 中的环境是什么」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 R Academy 课中编写并运行代码吗?
能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- R 中的环境是什么
- 词法作用域规则
- 全局作用域与局部作用域
- 创建并检查环境