5

谁能让我知道TCLupvar 0upvar 1TCL之间的区别,我们如何实时使用。请,如果有人举例解释,它会让我更清楚。

4

3 回答 3

10

当你调用一堆过程时,你会得到一堆堆栈帧。它在名字里。我们可以这样想象:

美国广播公司 123 456
   公元前 321 456
      cde 654 321

好的,所以我们有abccallbcd呼叫cde。简单的。

和在查找要链接到的变量0时说明要向上堆栈多少级。意味着上升一个级别(即,到当前帧的调用者),例如在我们的示例中从到到,将从上到一直到运行整个脚本和回调的全局评估级别。是这种情况的特例;这意味着在当前堆栈帧中进行查找。还可以通过将名称放在名称前面来使用堆栈底部的索引,因此表示全局框架,它首先调用。1upvar1cdebcd2cdeabc30##0#1

最常见的用法upvarupvar 1(如果你不考虑关卡,那就是它的作用)。upvar 0仅当您想要为变量获取不同(通常更易于使用)名称时才真正使用。下一个最常见的是upvar #0, 虽然global是一个更常见的简写形式(为了方便起见,它匹配名称的非限定部分)。其他形式很少见;例如,upvar 2通常表示代码非常混乱和纠结,upvar #1在 Tcl 8.6 的协程之前几乎没有人使用过。我从未见过upvar 3或从未见过upvar #2(尽管计算的级别指标存在于 Tcl 的某些对象系统中)。

示例upvar 1——按名称传递变量:

proc mult-by {varName multiplier} {
    upvar 1 $varName var
    set var [expr {$var * $multiplier}]
}

set x 2
mult-by x 13
puts "x is now $x"
# x is now 26

示例upvar 0——简化变量名:

proc remember {name contents} {
    global my_memory_array
    upvar 0 my_memory_array($name) var
    if {[info exist var]} {
        set var "\"$var $contents\""
    } else {
        set var "\"$name $contents\""
    }
}

remember x 123
remember y 234
remember x 345
remember y 456
parray my_memory_array
# my_memory_array(x) = ""x 123" 345"
# my_memory_array(y) = ""y 234" 456"
于 2015-05-12T12:34:40.650 回答
2

与 upvar 1 不同, upvar 0 为变量创建别名。例如:

    set a 4 
proc upvar1 {a} {
upvar 1 a b
incr a 4
incr b 3
puts "output is $a $b"
}
proc upvar0 {a} {
upvar 0 a b
incr a 4
incr b 3
puts "output is $a $b"
}
upvar1 $a
puts "in global frame value of a is  $a"

set a 4
upvar0 $a
puts "in global frame value of a is  $a"

输出:

output is 8 7
in global frame value of a is  7
output is 11 11
in global frame value of a is  4
于 2015-05-20T10:53:44.123 回答
1

好的,我认为一个示例将使差异变得非常清楚:

假设我们有一个函数 test_upvar1:

proc test_upvar1 {} {
    upvar 1 a b
    incr b
}

还有一个函数 test_upvar0:

proc test_upvar0 {} {
    upvar 0 a b
    incr b
}

现在我们设置变量 a 并调用这两个函数来看看会发生什么:

set a 5
test_upvar1

这将返回 6

set a 5
test_upvar0

将返回 1

发生这种情况是因为我们用零和一个选择我们的执行帧 0 链接在同一个执行帧 1 上一帧。

http://wiki.tcl.tk/1508

于 2015-05-12T11:59:15.643 回答