作用域

set alpha 1

proc myproc {} {
    puts $alpha
}

myproc

此代码不起作用,因为两个 alpha 位于不同的范围内。

命令 set alpha 1 在全局范围内创建一个变量(使其成为全局变量)。

命令 puts $alpha 在命令 myproc 执行时创建的范围内执行。

这两个范围是截然不同的。这意味着当 puts $alpha 试图查找名称 alpha 时,它找不到任何这样的变量。

但是,我们可以解决这个问题:

proc myproc {} {
    global alpha beta
    puts $alpha
}

在这种情况下,两个全局变量 alphabeta 在过程的范围内链接到别名变量(具有相同的名称)。从别名变量读取将检索全局变量中的值,并且写入它们会更改全局变量中的值。

更一般地说,upvar 命令为来自任何先前作用域的变量创建别名。它可以与全局范围一起使用(#0):

proc myproc {} {
    upvar #0 alpha alpha beta b
    puts $alpha
}

别名可以与链接到(alpha)或其他名称(beta / b)的变量同名。

如果我们从全局范围调用 myproc,这个变体也可以工作:

proc myproc {} {
    upvar 1 alpha alpha beta b
    puts $alpha
}

范围编号 1 表示先前范围呼叫者范围

除非你真的知道你在做什么,#001 是与 upvar 一起使用的唯一有意义的范围。 (upvar 0 为局部变量创建一个本地别名,而不是严格的作用域操作。)

其他一些语言通过花括号定义范围,让每个范围内运行的代码查看周围范围内的所有名称。在 Tcl 中,在调用过程时会创建一个单一的作用域,并且只有它自己的名称可见。如果过程调用另一个过程,则其作用域将堆叠在前一个作用域的顶部,依此类推。这意味着与仅具有全局范围和局部范围(使用子范围)的 C 风格语言相比,每个范围充当它已打开的任何范围的封闭(但不是立即可见)范围。过程返回时,其范围将被销毁。

文档: globalupvar