PAYATHON 2026

为什么 RStudio Terminal 中的函数定义没有随 Global Environment 更新?

数据小许

结论

这是正常行为。在 RStudio Terminal 中手动启动的 R 是独立进程,它的工作空间与 RStudio Console 使用的工作空间不同。Console 中更新的 foo 不会自动出现在 Terminal 的 R 会话中。

RStudio 的 Global Environment 面板通常显示主 R 会话的全局环境。Terminal 虽然嵌在同一个窗口里,但其中启动的 R 不共享这个环境,也不会默认自动同步。

为什么会看到旧定义?

Terminal 中的 R 启动时,如果恢复了保存的工作空间,例如 .RData,就会加载保存时的 foo。这是当时对象的快照,不会随其他会话中的修改而变化。

保存文件和执行代码也有区别:

  • 修改并保存 .Rmd,只会更新磁盘上的文件。
  • 在 Console 中执行定义 foo 的代码,会更新 Console 所属会话中的对象。
  • 在 Terminal 的 R 中执行同样的定义,会更新 Terminal 会话中的对象。

如果只编辑 .Rmd 而没有执行相应代码,Console 中的 foo 也可能仍是旧定义。

可以分别在 Console 和 Terminal 的 R 提示符下执行:

Sys.getpid()

如果得到的进程 ID 不同,就可以确认它们是独立进程。即使两边的 getwd() 相同,也不代表它们共享内存中的对象。

如何使用更新后的函数?

在 RStudio 中调试时,使用 Console

如果希望函数与 Global Environment 面板中的对象保持一致,可以在 RStudio Console 对应的会话中执行 .Rmd 里定义函数的代码块,然后调用函数。

例如,将返回值改为 3 后,执行:

foo <- function() {
  return(3)
}

foo()
# [1] 3

只保存 .Rmd 不会执行这段代码。Knit 或 Render 通常也会使用独立的执行会话,不应依靠渲染来更新当前 Console 中的对象。

两个会话都需要函数时,加载同一份 R 脚本

可以将函数定义放在单独的 functions.R 文件中:

foo <- function() {
  return(3)
}

然后分别在 Console 和 Terminal 的 R 中执行:

source("functions.R")
foo()

修改并保存 functions.R 后,需要在各个会话中重新运行 source(),才能更新各自的定义。相对路径以各会话的工作目录为准,必要时可以使用绝对路径。

不要直接用 source() 加载包含 Markdown 正文和代码围栏的 .Rmd 文件。可以执行其中的 R 代码块,或把可复用的函数提取到 .R 文件中。

临时传递对象时,显式保存和读取

如果要把 Console 中当前的 foo 传给 Terminal,可以通过文件传递。

在 Console 中执行:

saveRDS(foo, file = path.expand("~/foo-transfer.rds"))

在 Terminal 的 R 中执行:

foo <- readRDS(path.expand("~/foo-transfer.rds"))
foo

这会替换 Terminal 中当前的 foo。之后如果再次修改函数,需要重新保存和读取。示例文件名应避开已有的重要文件,因为 saveRDS() 会覆盖同名文件。

如果函数依赖其他对象、包或外部资源,还需要保证接收会话具备这些依赖。日常开发中,共享脚本并在需要时重新执行,通常比反复保存和恢复整个工作空间更容易追踪函数来自哪个版本。

备注:内容仅供参考。