0Pricing
R Academy · 课时

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 反馈 — 无需本地设置。

此课程中的所有课时

  1. R 中的环境是什么
  2. 词法作用域规则
  3. 全局作用域与局部作用域
  4. 创建并检查环境
← 返回 R Academy