TCL漫谈——upvar命令

上一篇 / 下一篇  2009-04-29 00:31:41 / 个人分类:TCL

核心是调用栈(call stack frame)的访问

我的理解。核心是调用栈(call stack frame)的访问。


stack frame可以理解为程序执行的环境(context)。当调用一个函数时,可以认为是在当前的frame里新建了一个stack frame,函数在这个新建的frame里执行,默认情况下它能访问到的变量也局限于这个frame。要访问这个frame之外的变量,有两种思路。

  1. 在当前frame中通过某种声明,从而可以直接使用这个变量。这可以通过"upvar"做到。
  2. 将要访问这个变量的代码放到变量所在的frame执行。这可能通过"uplevel"做到。

这就要告诉程序要访问某个特定frame的位置。比如下面的例子。

  1. uplevel #0 {puts $var_name}
  2. uplevel #1 {puts $var_name}
  3. uplevel 1 {puts $var_name}
  4. uplevel 2 {puts $var_name}<br>

其中#0, #1 是stack frame绝对位置。#0表示最顶层,也就是所谓”全局“那一层。第三行,第四行的1,2表示当前frame的上一层frame,和再上一层frame。上面的例子都表示在指定的stack frame时执行相应的命令,其中变量"var_name"也应该是声明在相应的frame里的。

/××××××××××××××××××××××××××××××××××××××××××××××
//gongxing:这里说得很透彻了,我很容易联想到upvar语法:
//upvar ?level? otherVar myVar ?otherVar myVar ...?
//里的level参数跟上面一样
//1:表示当前frame的上一层frame
//2:表示再上一层frame。
//所以编写下面代码验证
××××××××××××××××××××××××××××××××××××××××××××××/
proc three {y} {
    upvar 1 $y z       ;# tie the calling value to variable z
    upvar 2 x a        ;# Tie variable x two levels up  to a
    puts "three: Z: $z A: $a"  ;# Output the values, just to confirm
    set z 1            ;# Set z, the passed variable to 1;
    set a 2            ;# Set x, two layers up to 2;
}
proc two {y} {
    upvar $y z         ;# This ties the calling value to variable z
    puts "two: Z: $z"  ;# Output that value, to check it is 5
    three z            ;# call proc two, which will change the value
}
proc one {y} {
    set x "ok"
    two y
    puts $x
}
set y 5
one $y
//gongxing:y和z是层层引用,而x和a是上一层的上一层引用(蓝色部分),比对结果,three函数里的a引用到了one里的x,并
//改变了x的值

"uplevel"的用法简单来说也就是如此。"upvar"则是把指定frame里的变量拿到当前frame里来用。比如:

  1. upvar 1 var_name_outside
  2. var_name_inside

通过这样的声明之后,当前frame里访问变量"var_name_inside"实质上就是访问上一层frame里的变量"var_name_outside"。这跟C语言中的引用很类似。

说到这里,我们再看下面两条语句:

  1. global var_name
  2. upvar #0 var_name var_name<br>

它们是不是有着相同的作用呢。但global很大程度上要求你必须知道变量的名字,而upvar则不需要。比如自己写一个printvar的命令的话。

  1. # This does not work!
  2. proc printvar_global {var_name} {
  3. global $var_name
  4. puts $var_name
  5. }
  6.  
  7. # This works!
  8. proc printvar_upvar {var_name} {
  9. upvar #0 $var_name name
  10. puts $name
  11. }

这个例子可以很好的说明upvar的妙处来。


TAG:

 

评分:0

我来说两句

我的栏目

日历

« 2024-04-28  
 123456
78910111213
14151617181920
21222324252627
282930    

数据统计

  • 访问量: 8065
  • 日志数: 7
  • 建立时间: 2009-03-16
  • 更新时间: 2009-05-24

RSS订阅

Open Toolbar