我在TCL中有关于upvar命令的问题.使用upvar命令,我们在其他过程中引用了全局变量或局部变量.我看到了以下代码:
proc tamp {name1 name2} {
upvar $name1 Ronalod
upvar $name2 Dom
set $Dom "Dom"
}
Run Code Online (Sandbox Code Playgroud)
这个过程被称为tamp name1 name2
,并且没有全局变量name1,name2在它之外定义,这个upvar在这种情况下是如何工作的?
Don*_*ows 16
调用时upvar 1 $foo bar
,它会在调用者的作用域中找到名称在foo
变量中的变量,并将局部bar
变量作为其别名.如果变量不存在,则以未设置状态创建(即,变量记录存在但没有值.实际上,实现使用a NULL
来表示该信息,这就是Tcl没有NULL
等价的原因; NULL
表示非-existence)但仍然创建了链接.(它只会在本地范围被破坏时被拆除,或者upvar
用于将局部变量指向别的东西.)
因此,让我们看看你的代码是什么真正做:
proc tamp {name1 name2} {
upvar $name1 Ronalod
upvar $name2 Dom
set $Dom "Dom"
}
Run Code Online (Sandbox Code Playgroud)
第一行说,我们正在创建一个名为命令tamp
的程序,这一程序将有两个强制性的形式参数,而这些参数被称为name1
和name2
.
第二行表示我们在调用者中绑定一个变量名(1
来自我之前解释的级别指示符是可选的,但在惯用代码中强烈建议),该name1
变量由变量(即,过程的第一个参数)给出局部变量Ronalod
.从此以后,对该局部变量的所有访问(直到堆栈帧的生命结束)将实际对调用者中的绑定变量执行.
除了name2
(第二个参数)和Dom
(局部变量)之外,第三行几乎相同.
第四行实际上非常时髦.它读取Dom
变量以获取变量名称(即,在过程调用的第二个参数中命名的变量)并将该命名变量设置为该值Dom
.请记住,在Tcl中使用$
到阅读,从一个变量,而不是谈论变量.
过程调用的结果将是其正文中的最后一个命令的结果(即,文字Dom
因为它set
产生变量的内容作为其结果,它刚刚分配的值).(最后一行完全没有意义,因为它只是程序体的结束.)
调用此命令的最终结果实际上将是几乎什么都没有,除非第二个参数的名称包含一个variable Ronalod
或Dom
.这太令人困惑了.当然,令人困惑的一点是set
用变量第一个参数来说真的很时髦.(这几乎总是一个坏主意;它是坏代码气味的一个指标.)如果你使用它,事情本来会更简单:
set Dom "Dom"
Run Code Online (Sandbox Code Playgroud)
在这种情况下,Dom
耦合到的变量(即,由过程的第二个参数命名的变量)将被设置为Dom
; 变量实际上是通过引用传递的.这个额外的东西$
有很大的不同!