upvar的目的是什么?

use*_*285 3 tcl upvar

在我目前正在处理的TCL代码中,每个过程中的参数都被upvar赋予局部变量,然后使用.像这样的东西:

proc configure_XXXX { params_name_abc params_name_xyz} {
    upvar $params_name_abc abc
    upvar $params_name_xyz xyz
}
Run Code Online (Sandbox Code Playgroud)

从这里开始,abcxyz将用于做任何事情.我阅读了upvar TCL wiki,但无法理解其优点.我的意思是为什么我们只能使用已经接收的变量作为过程中的参数.有人可以详细说明吗?

Don*_*ows 6

我的意思是为什么我们只能使用已经接收的变量作为过程中的参数.

您可以.它只是让人讨厌.

通常,当您将变量的名称传递给命令时,命令可以修改该变量.这方面的经典例子是setincr命令,两者都以变量的名称作为它们的第一个参数.

set thisVariable $thisValue
Run Code Online (Sandbox Code Playgroud)

您也可以使用过程执行此操作,但是当需要在过程的调用者的上下文中定义的变量时,您需要从过程的上下文中访问该变量,该变量可能是命名空间,也可能是不同的局部变量框架.为此,我们通常使用upvar,它将局部变量的别名变为另一个上下文中的变量.

例如,这是重新实现incr:

proc myIncr {variable {increment 1}} {
    upvar 1 $variable v
    set v [expr {$v + $increment}]
}
Run Code Online (Sandbox Code Playgroud)

为什么写入局部变量v会导致调用者上下文中的变量更新?因为我们已经别名(在内部,它通过指向另一个变量的存储结构的指针设置;一旦upvar完成它就非常快).相同的基础机制用于globalvariable; 他们都被归结为快速变量别名.

你可以不用,只要你使用它uplevel,但这会更烦人:

proc myIncr {variable {increment 1}} {
    set v [uplevel 1 [list set $variable]]
    set v [expr {$v + $increment}]
    uplevel 1 [list set $variable $v]
}
Run Code Online (Sandbox Code Playgroud)

那太讨厌了!

或者,假设我们根本没有这样做.然后我们需要通过其值传递变量,然后分配结果:

proc myIncr {v {increment 1}} {
    set v [expr {$v + $increment}]
    return $v
}

# Called like this
set foo [myIncr $foo]
Run Code Online (Sandbox Code Playgroud)

有时是正确的事情,但却是完全不同的工作方式!

Tcl的核心原则之一是,您可以使用自己编写的命令完成使用标准库命令(例如ifor putsincr)所做的任何事情.没有关键字.当然可能存在一些效率问题,并且某些命令可能需要用另一种语言(例如C)才能正常工作,但语义不会使任何命令特殊.他们只是简单的命令.