Разница между упвар 0 и упвар 1 в TCL
Может кто-нибудь, дайте мне знать разницу между upvar 0
а также upvar 1
в TCL, как мы можем использовать в режиме реального времени. Пожалуйста, если кто-то объяснит с примером, это делает меня более ясным.
3 ответа
Когда вы вызываете кучу процедур, вы получаете стек фреймов стека. Это во имя. Мы могли бы визуализировать это так:
ABC 123 456 bcd 321 456 кд 654 321
Хорошо, у нас есть abc
призвание bcd
призвание cde
, Просто.
0
а также 1
в upvar
Скажите, сколько уровней нужно поднять в стеке при поиске переменной для ссылки. 1
означает перейти на один уровень вверх (т. е. к абоненту текущего кадра), скажем, из cde
в bcd
в нашем примере 2
будет идти от cde
вплоть до abc
а также 3
вплоть до глобального уровня оценки, где выполняются общие сценарии и обратные вызовы. 0
это частный случай этого; это значит сделать поиск в текущем стековом фрейме. Также есть возможность использовать индексирование из базы стека, поставив #
перед именем, так #0
указывает на глобальный фрейм, #1
первое, что он называет.
Наиболее распространенное использование upvar
является upvar 1
(и если вы пропустите уровень, это то, что он делает). upvar 0
действительно используется только тогда, когда вы хотите получить другое (обычно более удобное для работы) имя для переменной. Следующий наиболее распространенный upvar #0
, хоть global
это гораздо более распространенное сокращение (которое соответствует неквалифицированным частям имени для вашего удобства). Другие формы редки; например, upvar 2
обычно является признаком действительно запутанного и запутанного кода, и вряд ли кто-либо когда-либо использовал upvar #1
до сопрограмм Tcl 8,6. Я никогда не видел upvar 3
или же upvar #2
в дикой природе (хотя вычисленные индикаторы уровня присутствуют в некоторых объектных системах для Tcl).
Пример upvar 1
- передать переменную по имени:
proc mult-by {varName multiplier} {
upvar 1 $varName var
set var [expr {$var * $multiplier}]
}
set x 2
mult-by x 13
puts "x is now $x"
# x is now 26
Пример upvar 0
- упростить имя переменной:
proc remember {name contents} {
global my_memory_array
upvar 0 my_memory_array($name) var
if {[info exist var]} {
set var "\"$var $contents\""
} else {
set var "\"$name $contents\""
}
}
remember x 123
remember y 234
remember x 345
remember y 456
parray my_memory_array
# my_memory_array(x) = ""x 123" 345"
# my_memory_array(y) = ""y 234" 456"
В отличие от upvar 1, upvar 0 создает псевдоним для переменной. Например:
set a 4
proc upvar1 {a} {
upvar 1 a b
incr a 4
incr b 3
puts "output is $a $b"
}
proc upvar0 {a} {
upvar 0 a b
incr a 4
incr b 3
puts "output is $a $b"
}
upvar1 $a
puts "in global frame value of a is $a"
set a 4
upvar0 $a
puts "in global frame value of a is $a"
Выход:
output is 8 7
in global frame value of a is 7
output is 11 11
in global frame value of a is 4
Хорошо, я думаю, что пример прояснит разницу:
Допустим, у нас есть функция test_upvar1:
proc test_upvar1 {} {
upvar 1 a b
incr b
}
И функция test_upvar0:
proc test_upvar0 {} {
upvar 0 a b
incr b
}
Теперь мы устанавливаем переменную a и вызываем обе функции, чтобы увидеть, что происходит:
set a 5
test_upvar1
Это вернется 6
set a 5
test_upvar0
Вернется 1
Это происходит потому, что мы выбираем ноль и один наш кадр выполнения 0 ссылок в том же кадре выполнения 1 кадр выше.
Смотрите http://wiki.tcl.tk/1508