tcl中upvar和全局命令之间的实际区别是什么?

时间:2009-02-27 20:15:44

标签: tcl coding-style

我对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会更干净。我在这里错过了什么吗?

4 个答案:

答案 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 pageTcl manual page on namespaces

相关问题