作用域
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
}
在这种情况下,两个全局变量 alpha
和 beta
在过程的范围内链接到别名变量(具有相同的名称)。从别名变量读取将检索全局变量中的值,并且写入它们会更改全局变量中的值。
更一般地说,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
表示先前范围或呼叫者范围。
除非你真的知道你在做什么,#0
,0
和 1
是与 upvar
一起使用的唯一有意义的范围。 (upvar 0
为局部变量创建一个本地别名,而不是严格的作用域操作。)
其他一些语言通过花括号定义范围,让每个范围内运行的代码查看周围范围内的所有名称。在 Tcl 中,在调用过程时会创建一个单一的作用域,并且只有它自己的名称可见。如果过程调用另一个过程,则其作用域将堆叠在前一个作用域的顶部,依此类推。这意味着与仅具有全局范围和局部范围(使用子范围)的 C 风格语言相比,每个范围充当它已打开的任何范围的封闭(但不是立即可见)范围。过程返回时,其范围将被销毁。