无法理解TCL中的uplevel命令。

7

我有些困惑如何使用TCL中的uplevel。我正在阅读Brent Welch的《TCL和Tk实用编程》并且遇到一个uplevel的示例我无法理解。这里是示例:

proc lassign {valueList args} {
  if {[llength $args] == 0} {
    error "wrong # args:lassign list varname ?varname...?"
  }
  if {[llength $valueList] == 0} {
    #Ensure one trip through the foreach loop
    set valueList [List {}]
  }
  uplevel 1 [list foreach $args $valueList {break}]
  return [lrange $valueList [llength $args] end]
}

有人能给我解释一下吗?书中的解释对我来说不够有用:(
2个回答

7
uplevel命令在当前过程的作用域之外执行命令(或实际上是脚本)。特别地,在这种情况下,它是uplevel 1,意思是“在调用者中执行”。(您也可以使用uplevel #0在全局范围内执行,在其他地方也可以,例如调用者的调用者使用uplevel 2,但这确实非常罕见。)
解释该行其余部分:此处使用list的方式是构建一个无需替换的命令,其中包含四个单词:foreach、变量args的内容、变量valueList的内容和break(实际上不需要用花括号括起来)。这将为args列表中列出的每个变量分配来自valueList前面的值,然后停止,并在调用者的上下文中执行。
总体而言,该过程的工作方式与8.5中的内置lassign相同(假设输入列表和变量列表非空),但由于在范围之间交换复杂性等原因而较慢。

1
在8.6版本中,我们成功地将uplevel #1与协程结合使用。尽管这种形式已经合法存在了几十年,但这被认为是该形式有史以来的第一个实际应用。 - Donal Fellows
#<number> 语法的描述如下: "如果 level 包含 # 后跟一个数字,则该数字表示绝对级别编号。" http://www.tcl.tk/man/tcl8.5/TclCmd/uplevel.htm - Todd A. Jacobs
@DonalFellows 不要对顶级协程栈进行tailcall操作。 - Johannes Kuhn

5
proc a {} {
  set x a
  uplevel 3 {set x Hi}
  puts "x in a = $x"
}
proc b {} {
  set x b
  a
  puts "x in b = $x"
}
proc c {} {
  set x c
  b
  puts "x in c = $x"
}
set x main
c
puts "x in main == $x"

在这里,最内层的方法a将处于0级,b将处于1级,c将处于2级,而主程序将处于3级。因此,在过程a中,如果我更改level的值,那么我可以从方法“a”本身更改任何过程(即a、b、c或主过程)的变量x的值。尝试将level更改为3、2、1、0,看看输出的神奇结果。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接