upvar和uplevel: 核心是调用栈(call stack frame)的访问

@ 2009-07-19 17:13:59
标签:

    # 2008-05-06 10:34:30 by Sean Zhang

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

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

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

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

    uplevel #0 {puts $var_name}
    uplevel #1 {puts $var_name}
    uplevel 1   {puts $var_name}
    uplevel 2   {puts $var_name}
    

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

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

    upvar 1 var_name_outside var_name_inside
    

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

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

    global var_name
    upvar #0 var_name var_name
    

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

    # This does not work!
    proc printvar_global {var_name} {
        global $var_name
        puts $var_name
    } 
    # This works!proc printvar_upvar {var_name} {
        upvar #0 $var_name name
        puts $name
    }
    

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

    标签:

      分享到:
      comments powered by Disqus

      21/25ms