Команда предназначена для создания и управления областями имен для команд и переменных.
namespace ?option? ?arg?
Команда позволяет создавать, обращаться и уничтожать отдельные области имен для команд и переменных. Более детально назначение и использование команды описаны ниже см. Пространства имен. Действия, выполняемые командой, зависят от значения аргумента option. Ниже приведены возможные опции команды.
Позволяет захватить контекст текущей области имен для скрипта script с тем, чтобы потом использовать этот контекст при выполнении данного скрипта. Команда возвращает новый скрипт, в котором старый скрипт завернут в команду namespace code. Новый скрипт имеет две важные особенности: во-первых, он может быть вызван в произвольном пространстве имен, при этом реально он будет выполняться в текущем пространстве имен (том, в котором выполнялась команда namespace code). Во-вторых, к созданному таким образом скрипту можно дописывать произвольные аргументы и они действительно будут использоваться как дополнительные аргументы. Например, предположим, что команда
set script [namespace code {foo bar}]
выполняется в пространстве имен ::a::b. Тогда команда
eval " x y"
может быть выполнена в любом пространстве имен и будет иметь тот же эффект, что и команда
namespace eval ::a::b {foo bar x y}
Эта команда необходима потому, что расширения Tcl, например, Tk, обычно выполняют вызванные по событиям скрипты в глобальном пространстве имен. Обертывающая команда захватывает необходимую команду вместе с ее пространством имен и позволяет корректно выполнить ее позже по соответствующему вызову. Примеры использования данного механизма приведены ниже см. Правила видимости имен.
Выполняет скрипт в контексте пространства имен namespace. Эта команда не предназначена для непосредственного исполнения программистом. Ее вызовы создаются автоматически при использовании команды namespace code для создания скриптов, выполняемых в фоновом режиме, например, для Tk-виджетов. Команда namespace inscope похожа на команду namespace eval, но отличается от нее наличием возможности указывать дополнительные аргументы и тем, что пространство имен namespace должно существовать в момент выполнения команды. При выполнении команды первый аргумент рассматривается как список, к которому остальные аргументы добавляются как элементы списка. Так команда
namespace inscope ::foo a x y z
эквивалентна
namespace eval ::foo [concat a [list x y z]]
Такая семантика весьма удобна при формировании скриптов, выполняемых в фоновом режиме.
Пространство имен - это обособленный набор команд и переменных. Содержащиеся в нем команды и переменные не взаимодействуют с командами и переменными в других пространствах имен. В Tcl всегда был один такой набор, который мы будем называть глобальным пространством имен. В нем содержатся все глобальные переменные и команды. Команда namespace eval позволяет создавать другие пространства имен, например, команда
namespace eval Counter { namespace export Bump variable num 0 proc Bump {} { variable num incr num } }
создает новое пространство имен, содержащее переменную num и процедуру Bump. Команды и переменные в этом пространстве имен изолированы от других команд и имен в той же программе. Например, в глобальном пространстве имен может существовать другая команда Bump.
Переменные пространства имен напоминают глобальные переменные. Они существуют вне процедур, но могут использоваться в процедурах с помощью команды variable, как показано в предыдущем примере.
Пространства имен - динамические образования. В них можно в любой момент добавлять команды и переменные с помощью дополнительных команд namespace eval. Например, то же пространство имен, что и в предыдущем примере, можно было создать с помощью последовательности команд:
namespace eval Counter { variable num 0 proc Bump {} { variable num return [incr num] } } namespace eval Counter { proc test {args} { return } } namespace eval Counter { rename test "" }
Обратите внимание, что процедура test создана в пространстве имен Counter, а затем удалена с помощью команды rename.
Пространства имен могут иметь собственные вложенные пространства имен и образовывать иерархию пространств имен. Вложенное пространство имен содержится в своем предке и не может взаимодействовать с другими пространствами имен.
Каждое пространство имен имеет собственное имя, например history или ::safe::interp. Полные имена используются для указания команд, переменных или подпространств имен, содержащихся в соответствующем пространстве имен. Полные имена напоминают полные имена файлов в Unix или виджетов в Tk, но в качестве разделителей в них используется не слэш или точка, а двойное двоеточие "::". Самое верхнее или глобальное пространство имен имеет имя "" (пустая строка) и :: как синоним. Как пример, имя ::safe::interp::create ссылается на команду create в пространстве имен interp, которое является подпространством пространства имен ::safe, которое в свою очередь является подпространством глобального пространства имен ::.
Если вы хотите указать команду или переменную в другом пространстве имен, вы можете указать имя пространства имен, в котором она содержится. Например, из глобального пространства имен вызвать процедуру из пространства имен Counter можно следующим образом:
Counter::Bump 5 Counter::Reset
А вывести текущее значение переменной count можно с помощью команды
puts "count = ::num"
Если одно пространство имен содержит другое, может понадобиться более длинное имя. Если пространство имен Foo содержит пространство имен Counter, то чтобы вызвать процедуру Bump в последнем из глобального пространства имен, нужно воспользоваться именем
Foo::Counter::Bump 3
Полное имя может использоваться при создании или переименовании команд. Например, можно добавить процедуру в пространство имен Foo следующей командой:
proc Foo::Test {args} { return }
А переопределить ее в другом пространстве имен командой:
rename Foo::Test Bar::Test
Дополнительные замечания. Имена пространств имен, за исключением глобального, не могут быть пустой строкой. Сочетание :: запрещено в именах простых команд, переменных и пространств имен кроме как в роли разделителя имен пространств имен. Дополнительные символы : в полных именах игнорируются, то есть два или больше символов : подряд считаются одним разделителем. Сочетание :: в конце имени команды или переменной указывает на команду или переменную с именем {} (пустая строка). Однако в полном имени пространства имен :: на конце игнорируется.
Все Tcl-команды, которые работают с именами переменных и команд, поддерживают полные имена. Это значит, что можно использовать полные имена в таких командах, как set, proc, rename, или interp alias. Если вы используете абсолютное имя, начинающееся с ::, то такое имя всегда интерпретируется однозначно. Однако, если вы используете относительное имя, не начинающееся с ::, поиск объекта с соответствующим именем происходит по следующим правилам: команды и переменные сначала ищутся в текущем пространстве имен, а затем (если не найдены) - в глобальном. Имена пространств имен ищутся только в текущем пространстве имен.
В следующем примере
set traceLevel 0 namespace eval Debug { printTrace }
Tcl ищет переменную traceLevel в пространстве имен Debug и затем в глобальном пространстве имен. Аналогично ищется и процедура printTrace. Чтобы не оставлять неясностей, рассмотрим еще один пример:
set traceLevel 0 namespace eval Foo { variable traceLevel 3 namespace eval Debug { printTrace } }
Здесь Tcl ищет переменную traceLevel в пространстве имен Foo::Debug. Поскольку там ее нет, он продолжает поиск в глобальном пространстве имен. Переменная Foo::traceLevel в процессе поиска полностью игнорируется.
Чтобы разобраться в сложных ситуациях, можно использовать команду namespace which. Например, следующая команда:
namespace eval Foo::Debug {namespace which -variable traceLevel}
вернет ::traceLevel. С другой стороны, команда:
namespace eval Foo {namespace which -variable traceLevel}
вернет ::Foo::traceLevel.
Как уже упоминалось, относительные имена пространств имен ищутся иначе, чем имена команд и переменных. Они ищутся только в текущем пространстве имен. Это значит, что, например, команда namespace eval всегда создает потомка текущего пространства имен, если только имя нового пространства не начинается с ::.
Tcl не ограничивает доступ к командам, переменным или пространствам имен. Если вы указали имя, которое в соответствие с перечисленными выше правилами ссылается на нужный вам элемент, вы можете использовать этот элемент.
Переменные, определенные в данном пространстве имен, можно использовать в процедурах в этом же пространстве имен с помощью команды variable. Похожая на команду global, эта команда создает связь между локальной переменной в процедуре и одноименной переменной в пространстве имен. Если необходимо, эта команда также создает и инициализирует эту переменную (команда global только создает связь с переменной в глобальном пространстве имен). Команду variable можно не использовать, если вы всегда используете полное имя переменной.
Пространств имен часто используются для создания библиотек. Некоторые библиотечные команды могут использоваться так часто, что необходимость использования полных имен станет раздражать. Например, если все команды в такой библиотеке, как BLT, содержатся в пространстве имен Blt. Тогда вы смогли бы использовать их только следующим образом:
Blt::graph .g -background red Blt::table .g 0,0
Если Вы используете команды graph и table регулярно, предпочтительнее использовать их без префикса Blt::. Для этого достаточно импортировать эти команды в текущее пространство имен, например, следующим образом:
namespace import Blt::*
В результате выполнения этой команды все команды из пространства имен Blt будут экспортированы в текущее пространство имен, и вы сможете использовать их без соответствующего префикса:
graph .g -background red table .g 0,0
Команда namespace import импортирует только те команды, экспорт которых разрешен с помощью команды namespace export.
Как правило, не стоит импортировать все команды из пространства имен, так как при этом может быть сложно отследить все команды, которые вы получите. Лучше указать явно, какие именно команды вам нужны. Например, команда
namespace import Blt::graph Blt::table
импортирует только команды graph и table.
Если вы попытаетесь импортировать команду, которая уже существует в текущем пространстве имен, то вы получите ошибку. Это предупредит, например, попытки скопировать одну и ту же команду из двух разных библиотек. Однако время от времени (например, при отладке) у вас может появиться желание преодолеть данное ограничение. Для этого нужно указать в команде опцию -force, и тогда существующая команда будет заменена на импортируемую команду без сообщения об ошибке:
namespace import -force Blt::graph Blt::table
Если вам почему-либо надо прекратить использование библиотечной команды, это можно сделать следующим образом:
namespace forget Blt::*
Эта команда ищет в текущем пространстве имен все команды, импортированные из Blt, и удаляет их. Если таких команд не оказалось, команда ничего не делает. После исполнения команды namespace forget Blt::* команды из пространства имен Blt можно использовать только с префиксом Blt::.
Если вы удаляете команду из того пространства имен, где она была создана, например:
rename Blt::graph ""
то она будет удалена из всех пространств имен, в которые она была импортирована.
Вы можете разрешить экспорт команд из определенного пространства имен:
namespace eval Counter { namespace export Bump Reset variable num 0 variable max 100 proc Bump {{by 1}} { variable num incr num check return } proc Reset {} { variable num set num 0 } proc check {} { variable num variable max if { > } { error "too high!" } } }
После этого процедуры Bump и Reset можно импортировать, например, с помощью команды:
namespace import Counter::*
Но экспорт процедуры check не разрешен, и она не будет импортирована этой командой.
Команда namespace import позволяет импортировать только те команды, которые разрешено экспортировать из их пространства имен с помощью команды namespace export. Если в команде namespace import указана команда, которую нельзя экспортировать, она не будет импортирована в соответствующее пространство имен.