Tcl upvar的作用是什么?

Tcl upvar的作用是什么?,tcl,upvar,Tcl,Upvar,在我目前正在处理的TCL代码中,每个过程中的参数都是upvar,可以说是一个局部变量,然后使用。大概是这样的: proc configure_XXXX{params_name_abc params_name_xyz}{ upvar$params_name_abc upvar$params_name_xyz xyz } 从现在起,abc和xyz将被用来做任何事情。我读了这本书,但不明白它的优点。我的意思是,为什么我们不能在过程中使用已经收到的变量作为参数呢。谁能详细说明一下吗?使用upvar命令

在我目前正在处理的TCL代码中,每个过程中的参数都是
upvar
,可以说是一个局部变量,然后使用。大概是这样的:

proc configure_XXXX{params_name_abc params_name_xyz}{
upvar$params_name_abc
upvar$params_name_xyz xyz
}

从现在起,abc和xyz将被用来做任何事情。我读了这本书,但不明白它的优点。我的意思是,为什么我们不能在过程中使用已经收到的变量作为参数呢。谁能详细说明一下吗?

使用
upvar
命令可以修改块中的变量,并使此修改从父块可见

试试这个:

# a function that will modify the variable passed
proc set_upvar { varname } {
    upvar 1 $varname var
    puts "var was $var\n"
    set var 5
    puts "var is now $var\n"
}

# a function that will use the variable but that will not change it
proc set_no_upvar { var } {
    puts "var was $var\n"
    set var 6
    puts "var is now $var\n"
}

set foo 10

# note the lack of '$' here
set_upvar foo
puts "foo is $foo\n"

set_no_upvar $foo
puts "foo is $foo\n"

正如上面注释中提到的,它通常用于通过引用传递函数参数(通过引用调用)。一幅画要花上千言万语:

proc f1{x}{
upvar$x值
设置值0
}
程序f2{x}{
集x0
}
集x1
f1 x
卖出$x
集x1
f2 x
卖出$x
将导致:

$./call-by-ref.tcl
0
一,

使用
upvar
时,我们将变量
x
更改为函数外变量(从
1
更改为
0
),没有使用
upvar
时,我们没有更改

我的意思是,为什么我们不能在过程中使用已经收到的变量作为参数呢

你可以。它只是变得烦人

通常,将变量名称传递给命令时,命令可以修改该变量。这方面的经典示例是
set
incr
命令,这两个命令都将变量的名称作为其第一个参数

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

例如,这里是
incr
的重新实现:

proc myIncr {variable {increment 1}} {
    upvar 1 $variable v
    set v [expr {$v + $increment}]
}
为什么写入局部变量
v
会导致调用方上下文中的变量被更新?因为我们已经给它加了别名(在内部,它是通过指向另一个变量的存储结构的指针设置的;一旦
upvar
完成,它的速度非常快)。相同的底层机制用于
全局
变量
;它们都归结为快速变量别名

如果您使用
uplevel
,您也可以不使用它,但这会变得更烦人:

proc myIncr {variable {increment 1}} {
    set v [uplevel 1 [list set $variable]]
    set v [expr {$v + $increment}]
    uplevel 1 [list set $variable $v]
}
那太恶心了

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

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

# Called like this
set foo [myIncr $foo]
有时这是正确的,但却是一种完全不同的工作方式


Tcl的核心原则之一是,使用标准库命令(如
if
put
incr
)可以完成的任何事情都可以使用您自己编写的命令完成。没有关键字。当然,可能存在一些效率问题,一些命令可能需要用另一种语言(如C)来完成才能正常工作,但语义并没有使任何命令变得特别。它们都只是简单的命令。

您可以更改它们。它用于实现引用调用