Cuando el intérprete Tcl introduce un procedimiento escrito en Tcl, crea una tabla especial de variables locales para ese procedimiento mientras se está ejecutando su código. Esta tabla puede contener tanto variables locales "reales" como "enlaces" especiales a otras variables. Dichos enlaces son indistinguibles de las variables "reales" siempre que se trate de comandos Tcl (como set
, unset
, etc.).
Estos enlaces son creados por el comando upvar
, y es capaz de crear un enlace a cualquier variable en cualquier marco de pila (incluido el marco — alcance global 0).
Desde Tcl es muy dinámico, sus variables pueden ir y venir en cualquier momento y por lo tanto una variable vinculada al por upvar
podrían no existir en el momento que se crea un enlace a ella, observar:
% unset foo
can't unset "foo": no such variable
% proc test name { upvar 1 $name v; set v bar }
% test foo
bar
% set foo
bar
Tenga en cuenta que Primero demuestro que la variable llamada "foo" no existe, luego la configuro en un procedimiento que usa upvar
(y la variable se crea automáticamente) y luego demuestro que la variable existe después de que el procedimiento se haya cerrado.
También tenga en cuenta que no es upvar
acerca del acceso a las variables globales — esto generalmente se logra mediante los comandos global
y variable
; en su lugar, upvar
se utiliza para trabajar con variables en lugar de valores . Esto generalmente se necesita cuando necesitamos cambiar algo "en el lugar"; uno de los mejores ejemplos de esto es el comando lappend
que acepta el nombre de una variable que contiene una lista y agrega uno o más elementos a esa lista, cambiándola en su lugar. Para lograr esto, pasamos lappend
el nombre de una variable, no solo un valor de lista. Ahora compare esto con el comando linsert
que acepta un valor, no una variable, por lo que toma una lista y produce otra lista.
Otra cosa a tener en cuenta es que por defecto (en su forma de dos argumentos), upvar
enlaces a una variable con el nombre especificado un nivel por encima de la pila, no a una variable global. Es decir, usted puede hacer esto:
proc foo {name value} {
upvar $name v
set v $value
}
proc bar {} {
set x ""
foo x test
puts $x ;# will print "test"
}
En este ejemplo, el procedimiento de "foo" cambia la variable local al procedimiento de "barra".
Por lo tanto, para hacer más clara la intención, muchas personas prefieren especificar siempre el número de marcos de pila upvar
debe "subir", como en upvar 1 $varName v
que es el mismo que upvar $varName v
pero más claro.
Otra aplicación útil de esto se refiere a variables locales, mediante la especificación de cero niveles de la pantalla para subir — este truco es a veces útil para acceder a más convenientemente las variables de matrices:
proc foo {} {
set a(some_long_name) test
upvar 0 a(some_long_name) v
puts $v ;# prints "test"
upvar a(some_even_more_long_name) x
if {![info exists x]} {
set x bar
}
}
Como beneficio adicional, tenga en cuenta que upvar
también comprende números absolutos de marcos de pila que se especifican utilizando el prefijo "#", y "# 0" significa el alcance global. De esta manera, podría vincularse a una variable global, mientras que el procedimiento en su ejemplo original solo se vincularía a las variables globales si se ejecutara en el ámbito global.
si name1 y name2 son simplemente parámetros, luego en el proceso, ¿qué significa upvar? el mismo significado que "set name1 Ronaldo"? –
¡Hola! "upvar $ name1 Ronalod" significa literalmente crear una variable de ámbito local llamada Ronalod, que está vinculada a la variable referenciada por $ name1. Entonces, cualquier cambio en Ronalod también cambiará la variable referenciada por $ name1. Puedes ver que en mi ejemplo, el valor de "último" fue cambiado por establecer Dom "Dom". – TrojanName
gracias, pero en mi código, no hay variables globales name1, name2, así que si configura Dom "Dom", significa que la variable Dom se cambia, y la variable a la que hace referencia $ nombre1 también se cambia, pero en mi caso, la variable a la que hace referencia $ nombre1 no existe? –