6.2 环境
我们所创建的所有变量都需要存储在某处,即环境。环境本身也是另一种类型的变量,我们可以像对待其他变量一样地分配和操作它们,并将其以参数的形式传递到函数中。它们与列表密切相关,也能用于存储不同类型的变量。事实上,大部分用于列表的语法也同样适用于环境,而且我们可以强制地把列表当作环境使用(反之亦然)。
通常情况下,你不需要直接与环境打交道。例如,你在命令提示符下分配一个变量,它会自动进入全局环境(也称为用户工作区)中。当你调用函数时,将会自动创建一个环境用于存储与此函数相关的变量。不过,当你要了解变量的作用域或调试代码以检查调用栈时,掌握环境的基础知识将有所帮助。
有些烦人的是,环境的创建不是使用environment
函数(该函数将返回包含特定函数的环境),而用new.env
函数:
an_environment<-new.env()
向环境中分配变量的方式与列表完全相同。可以使用双方括号或美元符号运算符。和列表一样,环境变量的类型和大小可以不同:
an_environment[["pythag"]]<-c(12, 15, 20, 21) # 请查看http://oeis.org/A156683
an_environment$root<-polyroot(c(6, -5, 1))
2.3节中见到assign
函数还有一个可选的环境参数,用于指定变量的存储位置:
assign(
"moonday",
weekdays(as.Date("1969/07/20")),
an_environment
)
检索变量的方式也是如此:你可以使用列表的索引语法,或assign
的对立函数get
:
an_environment[["pythag"]]
## [1] 12 15 20 21
an_environment$root
## [1] 2+0i 3-0i
get("moonday", an_environment)
## [1] "Sunday"
可把环境参数传入ls
和ls.str
函数中,列出它的所有内容:
ls(envir = an_environment)
## [1] "moonday" "pythag" "root"
ls.str(envir = an_environment)
## moonday: chr "Sunday"
## pythag: num [1:4] 12 15 20 21
## root: cplx [1:2] 2+0i 3-0i
可用exists
函数测试变量是否在环境中:
exists("pythag", an_environment)
## [1] TRUE
很明显,使用as.list
和as. environment
函数能分别实现从环境到列表或相反过程的转换。在后一种情况中,还可以使用list2env
函数,它在创建环境时更为灵活:
# 转换为列表
(a_list<-as.list(an_environment))
## $pythag
## [1] 12 15 20 21
##
## $moonday
## [1] "Sunday"
##
## $root
## [1] 2+0i 3-0i
#...再转换回来。以下两行代码的效果一样。
as.environment(a_list)
## <environment: 0x000000004a6fe290>
list2env(a_list)
## <environment: 0x000000004ad10288>
所有的环境都是嵌套的,这意味着它们必须有一个父环境(位于顶端的特殊环境空环境除外)。默认情况下,exists
和get
函数也将在父环境中寻找变量。可通过给它们传入inherits = FALSE
来改变这种行为,使它们仅在指定的环境中搜索:
nested_environment<-new.env(parent=an_environment)
exists("pythag", nested_environment)
## [1] TRUE
exists("pythag", nested_environment, inherits=FALSE)
## [1] FALSE
注意
“框”(frame)这个词几乎可以与“环境”互换(要想了解此术语,请参考随R附带的语言定义手册2.1.10节)。这意味着工作环境中的一些函数名称里可能有“frame”,最常见的是
parent.frame
。
下列快捷函数可以同时访问全局环境(那些你从命令提示符中分配的变量的存储空间)和基础环境(那些R基础包中自带的基础函数和变量):
non_stormers<<-c(3, 7, 8, 13, 17, 18, 21) # 参见 http://oeis.org/A002312
get("non_stormers", envir=globalenv())
## [1] 3 7 8 13 17 18 21
head(ls(envir=baseenv()), 20)
## [1] "-" "-.Date" "-.POSIXt"
## [4] "!" "!.hexmode" "!.octmode"
## [7] "!=" "$" "$.data.frame"
## [10] "$.DLLInfo" "$.package_version" "$<-"
## [13] "$<-.data.frame" "%%" "%*%"
## [16] "%/%" "%in%" "%o%"
## [19] "%x%" "&"
在另外两种情况下也可能遇到环境。首先,当调用函数时,函数所定义的所有变量都被存储在属于该函数的环境中(函数及其环境有时称为闭包)。其次,当加载包时,包中的函数将存储于其搜索路径的环境中。这将在第10章中讨论。