2009-02-27 104 views
1

我对TCL相当陌生,并且正在为其他人开发的某些代码提供QA(没有真正的!)。在这个特定的程序中有很多很多全局变量,有时我会看到upvar被使用,通常与全局一起使用。我明白upvar会模仿通过引用,但下面两个procs之间的实际区别是什么?upvar和全局命令在tcl中的实际区别是什么

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

请注意,你并没有将变量'myBigFatGlobalVariable'设置为3,而是将'hello'设置为3.你还在第一行中拼写'myBigFatGlobalVariable' $ dereferences它的前缀变量 它有帮助如果你张贴代码吨工作。 – 2009-03-03 23:08:13

回答

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”作为参数,然后在堆栈中的一个帧和局部变量“local”之间创建名为“hello”的变量之间的链接。设置“本地”的效果是在堆栈中设置“hello”一帧。

要看到:


myFirstProc $myBigFatGlobalVariable 3 
puts $hello ;# ==> 9 
unset hello 
mySecondProc 3 
puts $hello ;# ==> can't read "hello": no such variable 

如果你真的想设置全球性的 “你好” 从mySecondProc,你需要添加global $myBigFatGlobalVariable

+0

谢谢,格伦。这正是我正在寻找的解释! – 2009-03-16 23:13:43

1

区别在于upvar 1 $ var 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与全局相同。

+0

谢谢!我认为答案是,在这种情况下,没有真正的区别,因为两个特效都被称为同一级别。如果mySecondProc调用myFirstProc,我会看到不同之处。 – 2009-02-27 21:05:11

4

他们是相似但略有不同。

upvar允许您访问调用堆栈中x个级别的变量。 它们不一定需要是全局变量。

您可以使用upvar模拟全局,方法是传递upvar#0 varName localVarName 在这种情况下,您将使用本地名称获取全局变量。

要模拟按引用传递,您需要传递变量的名称,然后调用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只是一种方式来获得在从调用堆栈变量。 (调用函数),包括'全局'堆栈。

0

你是在说:

有很多很多全球 变量在这个特定的程序

我的经验e与中等到非常大的Tcl应用程序(20k +行!)是使用名称空间将显着帮助在大量全局变量中获取结构。

好的部分是,您可以在每次为代码创建新模块时迭代地添加它们,或者重构一些代码。

namespace eval module1 { 
    variable counter 
    variable name 
} 

namespace eval module2 { 
    variable n 
    variable names 
} 

您可以通过模块1参考这些::计数器(就像你可以参考一个全局变量::计数器

wiki namespace pageTcl manual page on namespaces关于命名空间的更多信息。

相关问题