我对TCL很新,并且正在为其他人开发的一些代码提供QA(不是真的!)。在这个特定的程序中有很多很多的全局变量,我有时会看到使用upvar,通常与global一起使用。我知道upvar模拟pass-by-reference,但是下面两个proc之间的实际区别是什么?
set myBigFatGloblVariable "hello"
proc myFirstProc { var1 var2 } {
upvar 1 $var1 local
set local [expr $var2 * 3]
}
proc mySecondProc { var2 } {
global myBigFatGlobalVariable
set $myBigFatGlobalVariable [expr $var2 * 3]
}
myFirstProc $myBigFatGlobalVariable 3
mySecondProc 3
在我看来,myFirstProc会更干净。我在这里错过了什么吗?
答案 0 :(得分:4)
它们相似但略有不同。
upvar允许您在调用堆栈中访问x级别的变量。 它们不一定需要是全局变量。
您可以通过传递upvar#0 varName localVarName来使用upvar来模拟全局 在这种情况下,您将获得具有本地名称的全局变量。
要通过引用模拟传递,您将传递变量的名称,然后在该名称上调用upvar。
如果您知道变量的名称,则可以按原样使用它。
请注意以下代码:
# here there is only 1 global variable, but we also need to access to variables defined in the calling functions
proc p3 {} {
# upvar defaults to 1, so not needed to put in here
# also notice you can call upvar on more than one variable
upvar dog myDog horse myHorse cat myCat
upvar 2 cow myCow alpha myAlpha
upvar #0 samurai mySamurai
puts "Level 1: $myDog $myHorse $myCat"
puts "Level 2: $myCow $myAlpha"
puts "Global : $mySamurai"
}
proc p2 {} {
set dog "bowow"
set horse "niegh"
set cat "meow"
p3
}
proc p1 {} {
set cow "moo"
set alpha "beta"
p2
}
set samurai "japan"
p1
返回
Level 1: bowow niegh meow
Level 2: moo beta
Global : japan
upvar只是从调用堆栈中获取变量的一种方法。 (调用函数)包括'全局'堆栈。
答案 1 :(得分:2)
set myBigFatGlobalVariable "hello"
proc myFirstProc { var1 var2 } {
upvar 1 $var1 local
set local [expr $var2 * 3] }
proc mySecondProc { var2 } {
global myBigFatGlobalVariable
set $myBigFatGlobalVariable [expr $var2 * 3] }
myFirstProc $myBigFatGlobalVariable 3
mySecondProc 3
你的两个触发器之间的最大区别是:myFirstProc设置全局“你好”,mySecondProc设置本地“你好”。
mySecondProc引用全局myBigFat ...来获取值“hello”,但不会改变“hello”变量的范围。
myFirstProc接收值“hello”作为参数,然后在堆栈上一帧的名为“hello”的变量与本地变量“local”之间创建链接。设置“local”具有在堆栈中向上设置“hello”的效果。
要查看:
myFirstProc $myBigFatGlobalVariable 3
puts $hello ;# ==> 9
unset hello
mySecondProc 3
puts $hello ;# ==> can't read "hello": no such variable
如果您真的想从mySecondProc设置全局“hello”,则需要添加global $myBigFatGlobalVariable
答案 2 :(得分:1)
不同之处在于upvar 1 $ var local使local从上面的$ var中命名的变量中获取其值。所以在myBigFatGlobalVariable中,$ var不必在全局范围内定义。
proc p1 { var1 } {
upvar 1 $var1 local1
puts $local1
}
proc p2 { } {
set local2 "local2"
p1 local2
}
set global1 "global1"
p1 global1
p2
p1将从调用堆栈中它上面的级别1打印出var1的值。全局总是定义在顶层,因此upvar#0与全局相同。
答案 3 :(得分:0)
你在说:
全球有很多很多 这个特定程序中的变量
我对中到大型Tcl应用程序(20k +行!)的经验是,使用命名空间将极大地帮助在大量全局变量中获取结构。
不错的部分是,您可以在每次为代码创建新模块时通过迭代方式添加它们,或者重构一些代码。
namespace eval module1 {
variable counter
variable name
}
namespace eval module2 {
variable n
variable names
}
您可以通过module1 :: counter引用它们(正如您可以将全局变量称为:: counter
有关命名空间的详细信息,请参阅wiki namespace page和Tcl manual page on namespaces。