在我目前正在处理的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)
从这里开始,abc和xyz将用于做任何事情.我阅读了upvar TCL wiki,但无法理解其优点.我的意思是为什么我们只能使用已经接收的变量作为过程中的参数.有人可以详细说明吗?
我的意思是为什么我们只能使用已经接收的变量作为过程中的参数.
您可以.它只是让人讨厌.
通常,当您将变量的名称传递给命令时,命令可以修改该变量.这方面的经典例子是set
和incr
命令,两者都以变量的名称作为它们的第一个参数.
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
完成它就非常快).相同的基础机制用于global
和variable
; 他们都被归结为快速变量别名.
你可以不用,只要你使用它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的核心原则之一是,您可以使用自己编写的命令完成使用标准库命令(例如if
or puts
或incr
)所做的任何事情.没有关键字.当然可能存在一些效率问题,并且某些命令可能需要用另一种语言(例如C)才能正常工作,但语义不会使任何命令特殊.他们都只是简单的命令.