projman/hlp/ru/tcl/namespace.html
2018-02-05 17:23:37 +03:00

603 lines
40 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE HTML PUBLIC -//W3C//DTD HTML 4.01 Transitional//EN>
<html>
<head>
<title>namespace</title>
</head>
<body>
<h1>namespace</h1>
<p>Команда предназначена для создания и управления областями имен
для команд и переменных.</p>
<h2>СИНТАКСИС</h2>
<pre>
<strong>namespace</strong> ?<em>option</em>? ?<em>arg</em>?
</pre>
<h2>ОПИСАНИЕ</h2>
<p>Команда позволяет создавать, обращаться и уничтожать отдельные
области имен для команд и переменных. Более детально назначение
и использование команды описаны ниже см.
<a href=#Пространства имен>Пространства имен</a>.
Действия, выполняемые командой,
зависят от значения аргумента <em>option</em>. Ниже приведены
возможные опции команды.</p>
<dl>
<dt><strong>namespace</strong> <strong>children</strong> ?<em>namespace</em>?
?<em>pattern</em>?</dt>
<dd>Позволяет получить список областей-потомков для области имен
<em>namespace</em>. Если аргумент <em>namespace</em> отсутствует,
то возвращается список областей-потомков для текущего
пространства имен. Команда возвращает полные имена,
начинающиеся с <strong>::</strong>. Если указан аргумент <em>pattern</em>,
команда возвращает только те имена, которые удовлетворяют
шаблону <em>pattern</em>. Проверка на соответствие производится
по тем же правилам, что и в команде <a
href=glob.html><strong>glob</strong></a>. При этом шаблон,
начинающийся с <strong>::</strong>, используется непосредственно, в
противном случае используемый шаблон составляется из
<em>namespace</em> (или полного имени текущего пространства
имен) и <em>pattern</em>.</dd>
<dt><strong>namespace</strong> <strong>code</strong> <em>script</em></dt>
<dd><p>Позволяет захватить контекст текущей области имен для
скрипта <em>script</em> с тем, чтобы потом использовать этот
контекст при выполнении данного скрипта. Команда возвращает
новый скрипт, в котором старый скрипт <em>завернут</em> в
команду <strong>namespace code</strong>. Новый скрипт имеет две важные
особенности: во-первых, он может быть вызван в произвольном
пространстве имен, при этом реально он будет выполняться в
текущем пространстве имен (том, в котором выполнялась команда
<strong>namespace code</strong>). Во-вторых, к созданному таким образом
скрипту можно дописывать произвольные аргументы и они
действительно будут использоваться как дополнительные
аргументы. Например, предположим, что команда</p>
<pre>
set script [namespace code {foo bar}]
</pre>
<p>выполняется в пространстве имен <strong>::a::b</strong>. Тогда
команда</p>
<pre>
eval &quot; x y&quot;
</pre>
<p>может быть выполнена в любом пространстве имен и будет
иметь тот же эффект, что и команда</p>
<pre>
namespace eval ::a::b {foo bar x y}
</pre>
<p>Эта команда необходима потому, что расширения Tcl,
например, Tk, обычно выполняют вызванные по событиям скрипты в
глобальном пространстве имен. Обертывающая команда захватывает
необходимую команду вместе с ее пространством имен и позволяет
корректно выполнить ее позже по соответствующему
вызову. Примеры использования данного механизма приведены ниже
см. <a href=#ПРАВИЛА ВИДИМОСТИ ИМЕН>Правила
видимости имен</a>.</p>
</dd>
<dt><strong>namespace current</strong></dt>
<dd>Позволяет получить полное имя текущей области имен. Хотя
реальное имя глобального пространства имен &quot;&quot;
(пустая строка), эта команда возвращает для него <strong>::</strong>,
поскольку это часто бывает удобнее при программировании.</dd>
<dt><strong>namespace</strong> <strong>delete</strong> ?<em>namespace</em>
<em>namespace</em>...?</dt>
<dd>Позволяет удалить одну или несколько областей имен, при этом
удаляются все переменные, процедуры и области-потомки заданной
области имен. Если внутри одного из удаляемых пространств имен
выполняется какая-либо процедура, оно будет сохранено до
завершения процедуры, но помечено, как приготовленное к
удалению, чтобы исключить вызов других процедур. Если
указанное пространство имен не существует, команда возвращает
ошибку. Если ни одно пространство имен не указано, команда не
делает ничего.</dd>
<dt><a name=eval></a><strong>namespace</strong> <strong>eval</strong>
<em>namespace</em> <em>arg</em> ?<em>arg</em>...?</dt>
<dd>Позволяет активизировать пространство имен <em>namespace</em>
и выполнить в его контексте заданный код. Если пространство
имен <em>namespace</em> не существует, оно будет создано. Если
пространство имен должно быть предком несуществующего
пространства имен, то оно тоже создается. Если задано более
одного аргумента, все они объединяются в одну строку через
пробел (как при выполнении команды <a href=
eval.html><strong>eval</strong></a>) и полученный скрипт
выполняется.</dd>
<dt><strong>namespace</strong> <strong>export</strong> ?<strong>-clear</strong>?
?<em>pattern</em> <em>pattern</em>...?</dt>
<dd>Позволяет указать, какие команды разрешено экспортировать из
данного пространства имен. Эти команды потом могут быть
импортированы в другие пространства имен с помощью команды
<strong>namespace</strong> <strong>import</strong>. Можно разрешать экспорт как
команд, созданных в данном пространстве имен, так и команд,
ранее импортированных из других пространств. Команда,
разрешаемая для экспорта, может в данный момент не
существовать. Каждый из шаблонов <em>pattern</em> может
содержать специальные символы как в команде <a href=
glob.html><strong>glob</strong></a>, но не может содержать имени
пространства имен. То есть шаблон может указывать команды
только в текущем пространстве имен. Каждый из шаблонов
добавляется к списку шаблонов команд, разрешенных для импорта
из данного пространства имен. Если в команде указан флаг
<strong>-clear</strong>, команда предварительно удаляет старый
список. Если не указаны ни флаг, ни шаблоны, команда
возвращает текущий список шаблонов.</dd>
<dt><strong>namespace</strong> <strong>forget</strong> ?<em>pattern</em>
<em>pattern</em>...?</dt>
<dd>Удаляет из пространства имен ранее импортированные команды.
Каждый образец <em>pattern</em> должен быть полным именем
команды с указанием хотя бы одного пространства имен и может
содержать специальные символы, как в команде <a
href=glob.html><strong>glob</strong></a>, например: <strong>foo::x</strong>
или <strong>a::b::p*</strong>. Специальные символы нельзя использовать в
именах пространств имен. При выполнении данной команды сначала
ищутся команды, удовлетворяющие шаблону и разрешенные к
экспорту из соответствующих пространств имен. Далее
проверяется, какие из них были импортированы в текущее
пространство имен. После чего импортированные команды
удаляются. То есть команда выполняет действия, противоположные
действиям команды <strong>namespace import</strong>.</dd>
<dt><a name=import></a><strong>namespace</strong>
<strong>import</strong> ?<strong>-force</strong>? ?<em>pattern</em> <em>pattern</em>...?</dt>
<dd>Импортирует команды в текущее пространство имен. Каждый
образец <em>pattern</em> должен быть полным именем команды с
указанием хотя бы одного пространства имен и может содержать
специальные символы, как в команде <a href=
glob.html><strong>glob</strong></a>, например <strong>foo::x</strong> или
<strong>a::b::p*</strong>. Специальные символы нельзя использовать в
именах пространств имен. Все команды, которые удовлетворяют
шаблонам и разрешены для экспорта, добавляются к текущему
пространству имен. Для этого в текущем пространстве имен
создается новая команда, которая указывает на экспортируемую
команду в исходном пространстве имен. При вызове этой новой
команды она вызывает исходную команду. Если в текущем
пространстве имен уже есть команда с таким именем,
возвращается ошибка, если не указана опция <strong>-force</strong>. В
противном случае импортируемая команда заменяет команду,
определенную ранее. Команда <strong>namespace import</strong>
импортирует в текущее пространство имен только те функции,
которые в момент исполнения существуют в соответствующем
пространстве имен. Если позже там будут созданы новые команды
с именами, удовлетворяющими шаблонам, разрешающим экспорт, и
шаблонам, определяющим импорт, то они не импортируются
автоматически.</dd>
<dt><strong>namespace</strong> <strong>inscope</strong> <em>namespace</em> <em>arg</em>
?<em>arg</em>...?</dt>
<dd><p>Выполняет скрипт в контексте пространства имен
<em>namespace</em>. Эта команда не предназначена для
непосредственного исполнения программистом. Ее вызовы
создаются автоматически при использовании команды
<strong>namespace code</strong> для создания скриптов, выполняемых в
фоновом режиме, например, для Tk-виджетов. Команда
<strong>namespace inscope</strong> похожа на команду <strong>namespace
eval</strong>, но отличается от нее наличием возможности
указывать дополнительные аргументы и тем, что пространство
имен <em>namespace</em> должно существовать в момент
выполнения команды. При выполнении команды первый аргумент
рассматривается как список, к которому остальные аргументы
добавляются как элементы списка. Так команда</p>
<pre>
namespace inscope ::foo a x y z
</pre>
<p>эквивалентна</p>
<pre>
namespace eval ::foo [concat a [list x y z]]
</pre>
<p>Такая семантика весьма удобна при формировании скриптов,
выполняемых в фоновом режиме.</p>
</dd>
<dt><strong>namespace</strong> <strong>origin</strong> <em>command</em></dt>
<dd>Возвращает полное имя оригинальной команды <em>command</em>,
от которой происходит заданная импортированная команда. При
импорте команды в текущем пространстве имен создается новая
команда, которая указывает на экспортируемую команду в
исходном пространстве имен. Если команда последовательно
импортировать в пространства имен <em>a</em>, <em>b</em>, ...,
<em>n</em>, причем в каждое последующее пространство имен она
импортировалась из предыдущего, то <strong>namespace origin</strong>
вернет полное имя команды в первом пространстве имен, то есть
<em>a</em>. Если команда <em>command</em> не импортирована, то
<strong>namespace origin</strong> вернет ее полное имя.
</dd>
<dt><strong>namespace</strong> <strong>parent</strong> ?<em>namespace</em>?</dt>
<dd>Возвращает полное имя родительского пространства имен для
пространства <em>namespace</em>. Если аргумент <em>namespace</em>
не указан, возвращает полное имя предка текущего пространства
имен.</dd>
<dt><strong>namespace</strong> <strong>qualifiers</strong> <em>string</em></dt>
<dd>Возвращает полное имя пространства имен для <em>string</em>,
то есть часть строки <em>string</em> от начала до последнего
символа <strong>::</strong> (но не включая его). Например, для строки
<strong>::foo::bar::x</strong> эта команда вернет <strong>::foo::bar</strong>, а
для <strong>::</strong> - &quot;&quot; (пустую строку). Команда является
парной для команды <strong>namespace tail</strong>. При выполнении
команды проверка существования соответствующих пространств
имен не производится.</dd>
<dt><strong>namespace</strong> <strong>tail</strong> <em>string</em></dt>
<dd>Возвращает простое имя, завершающее полное имя
<em>string</em>, то есть часть строки <em>string</em> от
последнего символа <strong>::</strong> (но не включая его) до конца
строки. Например, для строки <strong>::foo::bar::x</strong> эта
команда вернет <strong>x</strong>, а для <strong>::</strong> - &quot;&quot;
(пустую строку). Команда является парной для команды
<strong>namespace qualifiers</strong>. При выполнении команды проверка
существования соответствующих пространств имен не
производится.</dd>
<dt><strong>namespace</strong> <strong>which</strong> ?<strong>-command</strong>?
?<strong>-variable</strong>? <em>name</em></dt>
<dd>Рассматривает <em>name</em> как имя команды или переменной (в
зависимости от указанной опции; по умолчанию - как имя
команды) и возвращает ее полное имя. Например, если
<em>name</em> не существует в текущем пространстве имен, но
существует в глобальном, то возвращает полное имя в глобальном
пространстве имен. Если команда или переменная не существует,
данная команда возвращает пустую строку. Более подробно
правила поиска имен см. <a href=
#ПРАВИЛА ВИДИМОСТИ ИМЕН>Правила видимости имен</a>.</dd>
</dl>
<h2><a name=ЧТО ТАКОЕ ПРОСТРАНСТВО ИМЕН?></a>ЧТО ТАКОЕ
ПРОСТРАНСТВО ИМЕН?</h2>
<p>Пространство имен - это обособленный набор команд и
переменных. Содержащиеся в нем команды и переменные не
взаимодействуют с командами и переменными в других пространствах
имен. В Tcl всегда был один такой набор, который мы будем
называть глобальным пространством имен. В нем содержатся все
глобальные переменные и команды. Команда <strong>namespace eval</strong>
позволяет создавать другие пространства имен, например, команда
<pre>
namespace eval Counter {
namespace export Bump
variable num 0
proc Bump {} {
variable num
incr num
}
}
</pre>
<p>создает новое пространство имен, содержащее переменную
<strong>num</strong> и процедуру <strong>Bump</strong>. Команды и переменные в этом
пространстве имен изолированы от других команд и имен в той же
программе. Например, в глобальном пространстве имен может
существовать другая команда <strong>Bump</strong>.</p>
<p>Переменные пространства имен напоминают глобальные
переменные. Они существуют вне процедур, но могут использоваться
в процедурах с помощью команды <a href=
variable.html><strong>variable</strong></a>, как показано в
предыдущем примере.</p>
<p>Пространства имен - динамические образования. В них можно
в любой момент добавлять команды и переменные с помощью
дополнительных команд <strong>namespace eval</strong>. Например, то же
пространство имен, что и в предыдущем примере, можно было
создать с помощью последовательности команд:</p>
<pre>
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 &quot;&quot;
}
</pre>
<p>Обратите внимание, что процедура <strong>test</strong> создана в
пространстве имен <strong>Counter</strong>, а затем удалена с помощью
команды <a href=rename.html><strong>rename</strong></a>.
<p>Пространства имен могут иметь собственные вложенные
пространства имен и образовывать иерархию пространств имен.
Вложенное пространство имен содержится в своем предке и не может
взаимодействовать с другими пространствами имен.</p>
<h2><a name=ПОЛНЫЕ ИМЕНА></a>ПОЛНЫЕ ИМЕНА</h2>
<p>Каждое пространство имен имеет собственное имя, например <a
href=history.html><strong>history</strong></a> или
<strong>::safe::interp</strong>. Полные имена используются для указания
команд, переменных или подпространств имен, содержащихся в
соответствующем пространстве имен. Полные имена напоминают
полные имена файлов в Unix или виджетов в Tk, но в качестве
разделителей в них используется не слэш или точка, а двойное
двоеточие &quot;<strong>::</strong>&quot;. Самое верхнее или глобальное
пространство имен имеет имя &quot;&quot; (пустая строка) и
<strong>::</strong> как синоним. Как пример, имя
<strong>::safe::interp::create</strong> ссылается на команду <strong>create</strong>
в пространстве имен <a href=interp.html><strong>interp</strong></a>,
которое является подпространством пространства имен
<strong>::safe</strong>, которое в свою очередь является подпространством
глобального пространства имен <strong>::</strong>.</p>
<p>Если вы хотите указать команду или переменную в другом
пространстве имен, вы можете указать имя пространства имен, в
котором она содержится. Например, из глобального пространства
имен вызвать процедуру из пространства имен <strong>Counter</strong>
можно следующим образом:</p>
<pre>
Counter::Bump 5
Counter::Reset
</pre>
<p>А вывести текущее значение переменной <em>count</em> можно с
помощью команды</p>
<pre>
puts &quot;count = ::num&quot;
</pre>
<p>Если одно пространство имен содержит другое, может понадобиться
более длинное имя. Если пространство имен <strong>Foo</strong> содержит
пространство имен <strong>Counter</strong>, то чтобы вызвать процедуру
<strong>Bump</strong> в последнем из глобального пространства имен, нужно
воспользоваться именем</p>
<pre>
Foo::Counter::Bump 3
</pre>
<p>Полное имя может использоваться при создании или переименовании
команд. Например, можно добавить процедуру в пространство имен
<strong>Foo</strong> следующей командой:</p>
<pre>
proc Foo::Test {args} { return }
</pre>
<p>А переопределить ее в другом пространстве имен командой:</p>
<pre>
rename Foo::Test Bar::Test
</pre>
<p>Дополнительные замечания. Имена пространств имен, за
исключением глобального, не могут быть пустой строкой.
Сочетание <strong>::</strong> запрещено в именах простых команд,
переменных и пространств имен кроме как в роли разделителя имен
пространств имен. Дополнительные символы <strong>:</strong> в полных
именах игнорируются, то есть два или больше символов <strong>:</strong>
подряд считаются одним разделителем. Сочетание <strong> ::</strong> в
конце имени команды или переменной указывает на команду или
переменную с именем <strong>{}</strong> (пустая строка). Однако в полном
имени пространства имен <strong>::</strong> на конце игнорируется.</p>
<h2><a name=ПРАВИЛА ВИДИМОСТИ ИМЕН></a>ПРАВИЛА ВИДИМОСТИ ИМЕН</h2>
<p>Все Tcl-команды, которые работают с именами переменных и
команд, поддерживают полные имена. Это значит, что можно
использовать полные имена в таких командах, как <a href=
seek.html><strong>set</strong></a>, <a
href=proc.html><strong>proc</strong></a>, <a
href=rename.html><strong>rename</strong></a>, или <a href=
interp.html#alias><strong>interp alias</strong></a>. Если вы
используете абсолютное имя, начинающееся с <strong>::</strong>, то такое
имя всегда интерпретируется однозначно. Однако, если вы
используете относительное имя, не начинающееся с <strong>::</strong>,
поиск объекта с соответствующим именем происходит по следующим
правилам: команды и переменные сначала ищутся в текущем
пространстве имен, а затем (если не найдены) - в
глобальном. Имена пространств имен ищутся только в текущем
пространстве имен.</p>
<p>В следующем примере</p>
<pre>
set traceLevel 0
namespace eval Debug {
printTrace
}
</pre>
<p>Tcl ищет переменную <strong>traceLevel</strong> в пространстве имен <strong>
Debug</strong> и затем в глобальном пространстве имен. Аналогично
ищется и процедура <strong>printTrace</strong>. Чтобы не оставлять
неясностей, рассмотрим еще один пример:</p>
<pre>
set traceLevel 0
namespace eval Foo {
variable traceLevel 3
namespace eval Debug {
printTrace
}
}
</pre>
<p>Здесь Tcl ищет переменную <strong>traceLevel</strong> в пространстве имен
<strong>Foo::Debug</strong>. Поскольку там ее нет, он продолжает поиск в
глобальном пространстве имен. Переменная <strong>Foo::traceLevel</strong>
в процессе поиска полностью игнорируется.</p>
<p>Чтобы разобраться в сложных ситуациях, можно использовать
команду <strong>namespace which</strong>. Например, следующая команда:</p>
<pre>
namespace eval Foo::Debug {namespace which -variable traceLevel}
</pre>
<p>вернет <strong>::traceLevel</strong>. С другой стороны, команда:</p>
<pre>
namespace eval Foo {namespace which -variable traceLevel}
</pre>
<p>вернет <strong>::Foo::traceLevel</strong>.</p>
<p>Как уже упоминалось, относительные имена пространств имен
ищутся иначе, чем имена команд и переменных. Они ищутся только в
текущем пространстве имен. Это значит, что, например, команда
<strong>namespace eval</strong> всегда создает потомка текущего
пространства имен, если только имя нового пространства не
начинается с <strong>::</strong>.</p>
<p>Tcl не ограничивает доступ к командам, переменным или
пространствам имен. Если вы указали имя, которое в соответствие
с перечисленными выше правилами ссылается на нужный вам элемент,
вы можете использовать этот элемент.</p>
<p>Переменные, определенные в данном пространстве имен, можно
использовать в процедурах в этом же пространстве имен с помощью
команды <a href=variable.html><strong>variable</strong></a>. Похожая на
команду <a href=global.html><strong>global</strong></a>, эта команда
создает связь между локальной переменной в процедуре и
одноименной переменной в пространстве имен. Если необходимо, эта
команда также создает и инициализирует эту переменную (команда
<a href=global.html><strong>global</strong></a> только создает связь
с переменной в глобальном пространстве имен). Команду <a
href=variable.html><strong>variable</strong></a> можно не
использовать, если вы всегда используете полное имя
переменной.</p>
<h2>ИМПОРТ КОМАНД</h2>
<p>Пространств имен часто используются для создания
библиотек. Некоторые библиотечные команды могут использоваться
так часто, что необходимость использования полных имен станет
раздражать. Например, если все команды в такой библиотеке, как
BLT, содержатся в пространстве имен <strong>Blt</strong>. Тогда вы смогли
бы использовать их только следующим образом:</p>
<pre>
Blt::graph .g -background red
Blt::table .g 0,0
</pre>
<p>Если Вы используете команды <strong>graph</strong> и <strong>table</strong>
регулярно, предпочтительнее использовать их без префикса
<strong>Blt::</strong>. Для этого достаточно импортировать эти команды в
текущее пространство имен, например, следующим образом:</p>
<pre>
namespace import Blt::*
</pre>
<p>В результате выполнения этой команды все команды из
пространства имен <strong>Blt</strong> будут экспортированы в текущее
пространство имен, и вы сможете использовать их без
соответствующего префикса:</p>
<pre>
graph .g -background red
table .g 0,0
</pre>
<p>Команда <strong>namespace import</strong> импортирует только те команды,
экспорт которых разрешен с помощью команды <strong>namespace
export</strong>.</p>
<p>Как правило, не стоит импортировать все команды из пространства
имен, так как при этом может быть сложно отследить все команды,
которые вы получите. Лучше указать явно, какие именно команды
вам нужны. Например, команда</p>
<pre>
namespace import Blt::graph Blt::table
</pre>
<p>импортирует только команды <strong>graph</strong> и <strong>table</strong>.</p>
<p>Если вы попытаетесь импортировать команду, которая уже
существует в текущем пространстве имен, то вы получите
ошибку. Это предупредит, например, попытки скопировать одну и ту
же команду из двух разных библиотек. Однако время от времени
(например, при отладке) у вас может появиться желание преодолеть
данное ограничение. Для этого нужно указать в команде опцию
<strong>-force</strong>, и тогда существующая команда будет заменена на
импортируемую команду без сообщения об ошибке:</p>
<pre>
namespace import -force Blt::graph Blt::table
</pre>
<p>Если вам почему-либо надо прекратить использование библиотечной
команды, это можно сделать следующим образом:</p>
<pre>
namespace forget Blt::*
</pre>
<p>Эта команда ищет в текущем пространстве имен все команды,
импортированные из <strong>Blt</strong>, и удаляет их. Если таких
команд не оказалось, команда ничего не делает. После
исполнения команды <strong>namespace forget Blt::*</strong> команды из
пространства имен <em>Blt</em> можно использовать только с
префиксом <strong>Blt::</strong>.</p>
<p>Если вы удаляете команду из того пространства имен, где она
была создана, например:</p>
<pre>
rename Blt::graph &quot;&quot;
</pre>
<p>то она будет удалена из всех пространств имен, в которые она
была импортирована.</p>
<h2><a name=ЭКСПОРТ КОМАНД></a>ЭКСПОРТ КОМАНД</h2>
<p>Вы можете разрешить экспорт команд из определенного
пространства имен:</p>
<pre>
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 { &gt; } {
error &quot;too high!&quot;
}
}
}
</pre>
<p>После этого процедуры <strong>Bump</strong> и <strong>Reset</strong> можно
импортировать, например, с помощью команды:</p>
<pre>
namespace import Counter::*
</pre>
<p>Но экспорт процедуры <strong>check</strong> не разрешен, и она не будет
импортирована этой командой.</p>
<p>Команда <strong>namespace import</strong> позволяет импортировать
только те команды, которые разрешено экспортировать из их
пространства имен с помощью команды <strong>namespace export</strong>.
Если в команде <strong>namespace import</strong> указана команда,
которую нельзя экспортировать, она не будет импортирована в
соответствующее пространство имен.</p>
</body>
</html>