upvar
Имя
upvar — Создать ссылку на переменную в другом кадровом элементе стекаСинтаксис
upvar ?level? otherVar myVar ?otherVar myVar ...?Описание
Эта команда позволяет одной или нескольким локальным переменным в текущей процедуре ссылаться на переменные во включающей процедурном вызове или на глобальные переменные. Level может иметь любой из форм, разрешенных для команды uplevel, и может быть опущена (по умолчанию равна 1). Для каждого аргумента otherVar, команда upvar делает переменную с этим именем в процедурном кадре, заданном level (или на глобальном уровне, если level равен #0), доступной в текущей процедуре под именем, заданным в соответствующем аргументе myVar. Переменная, названная otherVar, не обязательно должна существовать во время вызова; она будет создана в первый раз, когда myVar будет обработана, как и обычная переменная. Не должно существовать переменной с именем myVar во время вызова upvar. MyVar всегда рассматривается как имя переменной, а не элемента массива. Возвращается ошибка, если имя похоже на элемент массива, например a(b). OtherVar может ссылаться на скалярную переменную, массив или элемент массива. Команда Upvar возвращает пустую строку.Команда upvar упрощает реализацию процедуры вызова по имени и также упрощает создание новых управляющих конструкций в качестве Tcl процедур. Например, рассмотрим следующую процедуру:
proc add2 name {
upvar $name x
set x [expr {$x + 2}]
} Если add2 вызывается с аргументом, задающим имя переменной, она добавляет два к значению этой переменной. Хотя add2 могла быть реализована с помощью uplevel вместо upvar, upvar делает проще для add2 доступ к переменной в кадре процедуры вызывающей.
namespace eval является ещё одним способом (помимо вызовов процедур), которым может измениться контекст именования Tcl. Она добавляет кадр вызова в стек для представления контекста именования. Это означает, что каждая команда namespace eval учитывается как ещё один уровень вызова для команд uplevel и upvar. Например, info level 1 вернёт список, описывающий команду, которая является либо внешним вызовом процедуры, либо внешней командой namespace eval. Также, uplevel #0 оценивает скрипт на верхнем уровне во внешнем пространстве имён (глобальное пространство имён).
Если переменная upvar разыменована (например, x в add2 выше), операция unset влияет на переменную, с которой она связана, а не на переменную upvar. Нет способа разыменовать переменную upvar, кроме выхода из процедуры, в которой она определена. Однако можно перенаправить переменную upvar, выполнив другую команду upvar.
Отслеживание и upvar
Upvar взаимодействует с отслеживанием простым, но, возможно, неожиданным образом. Если отслеживание переменной определено для otherVar, это отслеживание будет активировано действиями, связанными с myVar. Однако процедура отслеживания получит имя myVar, а не имя otherVar. Таким образом, выводом следующего кода будет «localVar», а не «originalVar»:proc traceproc { name index op } {
puts $name
}
proc setByUpvar { name value } {
upvar $name localVar
set localVar $value
}
set originalVar 1
trace variable originalVar w traceproc
setByUpvar originalVar 2 Если otherVar ссылается на элемент массива, тогда отслеживание переменных, установленных для всего массива, не будет вызвано при обращении к myVar (но отслеживание конкретного элемента по-прежнему будет вызываться). В частности, если массив является env, то изменения, внесённые в myVar, не будут правильно переданы подпроцессам.
Пример
Команда decr, которая работает как incr, за исключением того, что она вычитает значение из переменной, а не добавляет его:proc decr {varName {decrement 1}} {
upvar 1 $varName var
incr var [expr {-$decrement}]
} См. также
global, namespace, uplevel, variable
Licensed under Tcl/Tk terms
https://www.tcl.tk/man/tcl/TclCmd/upvar.htm
Licensed under Tcl/Tk terms
https://www.tcl.tk/man/tcl/TclCmd/upvar.htm