Нет, не совсем. Пространства имен и фреймы вызовов - это очень разные понятия. Пространство имен - это иерархическая структура имен, которая может устранить синонимы. В вашей программе могут быть три переменные с именем foo
, но они не будут сталкиваться, если вы поместите их в разные пространства имен. Пространства имен могут использоваться как для имен переменных, так и для команд. После создания с namespace eval
содержимое пространства имен всегда доступно, пока вы не назовете на нем namespace delete
.
Стек вызовов представляет собой последовательность кадров стека. Первый стек кадров # 0 всегда существует. Другие кадры стека создаются всякий раз, когда вызывается команда (это в основном используется для команд, которые являются определяемыми пользователем процедурами, «встроенные» команды следуют своим собственным правилам). Они снова уничтожаются, когда команда возвращается. Так что, если вы вызовите команду 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
}
только некоторые команды нажмите кадры стека. Те, о которых все знают, - это вызовы процедур и 'namespace eval'. (Есть несколько других, особенно в TclOO ...) –
Спасибо, @Hoodiecrow, вы заполнили некоторые детали. Многие поисковые запросы показали мне, что пространства имен отличаются от кадров вызовов. И это пространство имен является необязательным и, пожалуй, лучше всего избегать в небольших скриптах (но полезно для повторного использования кода). Кроме того, кадры вызова создаются всякий раз, когда вызывается процедура. Чтобы прояснить далее: Я сформулировал в моем вопросе что-то неверное? –
@ user901750: есть некоторые проблемные утверждения. Вы говорите, что стек стека иногда называют стеком вызовов. Это неправильно, но я полагаю, что это была ошибка? Команда 'proc' не создает фреймы стека (но команды, которые она создает, при вызове). Пространство имен не изменяет контекст именования Tcl, но 'namespace eval' делает (путем создания нового фрейма стека). 'upvar' и' uplevel' не работают (манипулируют) пространствами имен как таковые, но могут обращаться к переменным пространства имен так же, как любая другая команда, которая обрабатывает переменные. –