Kat*_*ana 5 variables scope r lexical lexical-scope
我是R的新手,当我阅读手册时,我遇到了一个关于词法范围的段落以及这个代码示例:
open.account <- function(total) {
list(
deposit = function(amount) {
if(amount <= 0)
stop("Deposits must be positive!\n")
total <<- total + amount
cat(amount, "deposited. Your balance is", total, "\n\n")
},
withdraw = function(amount) {
if(amount > total)
stop("You don't have that much money!\n")
total <<- total - amount
cat(amount, "withdrawn. Your balance is", total, "\n\n")
},
balance = function() {
cat("Your balance is", total, "\n\n")
}
)
}
ross <- open.account(100)
robert <- open.account(200)
ross$withdraw(30)
ross$balance()
robert$balance()
ross$deposit(50)
ross$balance()
ross$withdraw(500)
Run Code Online (Sandbox Code Playgroud)
所以,我理解上面的代码是做什么的,我想我仍然对它究竟是如何工作感到困惑.如果在函数执行完毕后仍然可以访问函数的"局部"变量,那么在不再需要变量时是不是很难或不可能预测?在上面的代码中,如果它被用作更大程序的一部分,那么"total"会保存在内存中直到整个程序完成吗?(基本上成为一个全局变量记忆)如果这是真的,不会这导致内存使用问题?
我在这个网站上看了另外两个问题:"Lexical Scoping如何实现?" 和"为什么词汇范围首选编译器?".答案就在我脑海中,但它让我想知道:如果(正如我猜测的那样)编译器不只是使所有变量都是全局的(内存方式)而是使用某种技术来预测某些变量何时不会是否需要被删除,不会做这项工作实际上使编译器上的事情变得更难而不是更容易?
我知道这有很多不同的问题,但任何帮助都会很好,谢谢.
OP似乎在寻找有关环境的澄清.
在R中,每个函数[1]都有一个封闭的环境.除了那些作为参数传入的对象或它在代码中创建的对象之外,它还是它所知道的对象集合.
在提示符下创建函数时,其环境是全局环境.这只是工作区中对象的集合,您可以通过键入来查看ls().例如,如果工作空间包含数据框Df,则可以创建如下函数:
showDfRows <- function()
{
cat("The number of rows in Df is: ", nrow(Df, "\n")
return(NULL)
}
Run Code Online (Sandbox Code Playgroud)
你的函数知道Df即使你没有把它作为一个参数传递; 它存在于funtion的环境中.环境可以嵌套,这就像包命名空间这样的工作方式.例如lm(y ~ x, data=Df),即使您的工作空间不包含任何被调用的对象,您也可以进行回归lm.这是因为全球环境的父母链包括功能stats所在的包lm.[2]
当函数在另一个函数内创建时,它们的封闭环境是其父函数的评估框架.这意味着子函数可以访问父级已知的所有对象.例如:
f <- function(x)
{
g <- function()
{
cat("The value of x is ", x, "\n")
}
return(NULL)
}
Run Code Online (Sandbox Code Playgroud)
请注意,g它不包含任何被调用的对象x,也不包含任何名为的参数x.但是,它仍然有效,因为它将x从其父级的评估框架中检索f.
这是上面的代码使用的技巧.运行时open_account,它会创建一个评估框架,用于执行其代码.open_account然后创建3个函数deposit,withdraw和balance.这3个中的每一个都具有作为其封闭环境的评估框架open_account.在这次评估框架有一个叫做变量total,其值由你传递,而且可以通过操纵deposit,withdraw和balance.
当open_account完成时,它返回一个列表.如果这是一个常规函数,它的评估框架现在将由R处理.但是,在这种情况下,R可以看到返回的列表包含需要使用该评估框架的函数; 所以框架继续存在.
那么,为什么罗斯和罗伯特的账户不会相互冲突呢?每次执行时open_account,R都会创建一个新的评估框架.打开Ross'和Robert的账号的帧是完全分开的,就像你跑lm(y ~ x, data=Df),如果你跑的话会有一个单独的框架lm(y ~ x, data=Df2).每次open_account返回时,它都会带来一个新环境,用于存储刚刚创建的余额.(这将还包含的新副本deposit,withdraw和balance功能,但一般我们都不能忽视用于此的内存.)
[1]技术上每一个封闭,但让我们不是泥泞的东西
[2]同样,名称空间和环境之间存在技术上的区别,但这并不重要