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

发布于 2024-07-14 11:16:35 字数 513 浏览 6 评论 0原文

我对 TCL 相当陌生,正在为其他人开发的一些代码提供质量保证(不是真的!)。 在这个特定的程序中有很多很多的全局变量,我有时会看到 upvar 被使用,通常与 global 结合使用。 我知道 upvar 模拟引用传递,但是以下两个过程之间的实际区别是什么?

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

I'm fairly new to TCL, and am providing QA on some code developed by others (no really!). There are lots and lots of global variables in this particular program, and I sometimes see upvar used, often in conjunction with global. I understand that upvar emulates pass-by-reference, but what would be the practical difference be between the two following procs?

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

It seems to me that myFirstProc would be cleaner and . Am I missing something here?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

野鹿林 2024-07-21 11:16:35

它们相似但又略有不同。

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 只是从调用堆栈获取变量的一种方法。 (调用函数)包括“全局”堆栈。

They are similar but subtly different.

upvar allows you access variables up x levels in the call stack.
They don't necessarily need to be global variables.

You can use upvar to emulate global by passing upvar #0 varName localVarName
You will get the global variable with a local name in that case.

To emulate pass by reference, you are pass the name of the variable, then call upvar on that name.

If you know the name of the variable, you can use it as is.

Observe the following code:

    # 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

This returns

    Level 1: bowow niegh meow
    Level 2: moo beta
    Global : japan

upvar is just a way to get at variables from the call stack. (calling functions) including the 'global' stack.

z祗昰~ 2024-07-21 11:16:35
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 设置global“hello”,mySecondProc 设置local“hello”。

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

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

The big difference between your two procs is this: myFirstProc sets the global "hello", mySecondProc sets the local "hello".

mySecondProc references the global myBigFat... to get the value "hello", but does not alter the scope of the "hello" variable.

myFirstProc receives the value "hello" as a parameter, and then creates a link between a variable named "hello" one frame up the stack and the local variable "local". Setting "local" has the effect of setting "hello" one frame up the stack.

To see:


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

If you really want to set the global "hello" from mySecondProc, you'll need to add global $myBigFatGlobalVariable

め七分饶幸 2024-07-21 11:16:35

不同之处在于 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 与全局变量执行相同的操作。

The difference is that upvar 1 $var local makes local take its value from the variable named in $var from the level above. So in myBigFatGlobalVariable $var does not have to be defined at the global scope.

proc p1 { var1 } {
upvar 1 $var1 local1
puts $local1
}

proc p2 { } {
set local2 "local2"
p1 local2
}

set global1 "global1"
p1 global1
p2

p1 will print out the value of var1 from the level 1 above it in the call stack. A global is always defined at the top level so upvar #0 does the same thing as global.

︶葆Ⅱㄣ 2024-07-21 11:16:35

你是说:

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

我对中型到超大型 Tcl 应用程序(20k+ 行!)的经验是,使用名称空间将极大地帮助在大量全局变量中获取结构。

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

namespace eval module1 {
  variable counter
  variable name
}

namespace eval module2 {
  variable n
  variable names
}

您可以通过 module1::counter 引用它们(就像您可以将全局变量引用为 ::counter

参见 wiki 命名空间页面有关命名空间的 Tcl 手册页面 有关命名空间的更多信息。

You are saying:

There are lots and lots of global
variables in this particular program

My experience with medium to very large Tcl applications (20k+ lines!) is that using namespaces will significantly help getting structure within the large amount of global variables.

The nice part is, is that you can add them iteratively everytime you create a new module to your code, or by refactoring some of your code.

namespace eval module1 {
  variable counter
  variable name
}

namespace eval module2 {
  variable n
  variable names
}

You can refer to them via module1::counter (just as you can refer to a global variable as ::counter

See the wiki namespace page and the Tcl manual page on namespaces for more information on namespaces.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文