В чем разница между пространством имен TCL и фреймом стека?
Upvar создает ссылку на переменную в другом кадре стека, иногда называемом стеком вызовов, или в другой области видимости.
Upvar также используется для создания псевдонима для глобальной (или пространства имен) переменной 2. Но пространство имен создается только командой namespace eval. Новый кадр стека создается командой proc.
Пространства имен и стеки вызовов, по-видимому, являются двумя способами изменения контекста именования TCL. Upvar и Uplevel могут работать как в пространствах имен, так и в стеках вызовов.
Я правильно понял? Я еще не видел прямого сравнения между стеками вызовов и пространствами имен, поэтому мой вопрос.
1 ответ
Нет не совсем Пространства имен и фреймы вызовов - это очень разные понятия. Пространство имен - это иерархическая структура имен, которая может устранить неоднозначность синонимов. У вас может быть три переменные foo
в вашей программе, но они не будут конфликтовать, если вы поместите их в разные пространства имен. Пространства имен могут использоваться как для имен переменных, так и для команд. Однажды созданный с namespace eval
содержимое пространства имен всегда доступно, пока вы не позвоните namespace delete
в теме.
Стек вызовов - это последовательность кадров стека. Первый кадр стека, #0, всегда существует. Другие стековые фреймы создаются всякий раз, когда вызывается команда (в основном это команды, определяемые пользователем, "встроенные" команды следуют своим собственным правилам). Они уничтожаются снова, когда команда возвращается. Поэтому, если вы вызываете команду A, а A вызывает команду B, а B вызывает команду C, у вас есть стек вызовов, который выглядит следующим образом:
#3 : <C's variables>
#2 : <B's variables>
#1 : <A's variables>
#0 : <global and namespace variables>
Каждый стековый фрейм является областью в том смысле, что только переменные, созданные там или импортированные в него, могут быть доступны, если вы не используете upvar
, Все остальное скрыто. В большинстве языков программирования имена из внешней области видимости, такой как глобальная область, могут быть автоматически доступны из внутренней области видимости. Не так в Tcl.
С помощью upvar
вы можете позволить команде смотреть на вещи вне ее собственного стекового фрейма. C мог бы, например, использовать upvar #0 foo bar
создать псевдоним (bar
) для глобальной переменной foo
или используйте upvar 1 baz qux
(обратите внимание, без #), чтобы создать псевдоним (qux
) для переменной baz
в кадре стека B.
uplevel
Команда может использоваться в том же ключе для выполнения скрипта в другом фрейме стека, включая глобальный. Во время выполнения сценарий может получить доступ ко всему, что находится в этом кадре стека, но не к чему-либо другому, включая переменные в кадре стека, которые uplevel
был вызван из.
C может также создать псевдоним для переменной пространства имен ::abc::def
с помощью upvar #0 ::abc::def ghi
, но не делай этого, используй namespace upvar ::abc def ghi
вместо.
Вместо upvar #0 foo foo
ты можешь использовать global foo
импортировать глобальную переменную. Внутри команды, определенной в пространстве имен, variable
Команда может импортировать переменные, определенные в том же пространстве имен.
Это часто полезно для upvar
или же uplevel
в #0 (глобальный фрейм) или 1 (фрейм вызывающего). Использование других номеров кадров подвержено ошибкам и, как правило, свидетельствует о плохой конструкции. Вызов upvar 0 foo bar
создает псевдоним (bar
) для переменной (foo
) в одном кадре стека, что может быть удивительно полезным.
Команды, которые вызываются обрабатываемыми событиями, выполняются вне стека вызовов, используя глобальный уровень. У них нет возможности получить доступ к активным кадрам стека и получить доступ к переменным, которые там находятся.
Простая демонстрация:
namespace eval ::abc {
variable def 42
proc xyz {} {
variable def
}
}
set foo 1138
proc A {} {
B
}
proc B {} {
set baz 1337
C
}
proc C {} {
upvar #0 foo bar
puts $bar
upvar 1 baz qux
puts $qux
namespace upvar ::abc def ghi
puts $ghi
}