Переменная в пространстве имен TCL - PullRequest
2 голосов
/ 20 февраля 2012

У меня есть вопрос о переменных в пространстве имен TCL.

У меня есть два файла .tcl, a.tcl, b.tcl, я определяю одну и ту же глобальную переменную в этих двух файлах, например:

a.tcl

variable same "hello1"

b.tcl

variable same "hello2"
proc use {} {
   puts same
}

но в b.tcl я пытаюсь определить процедуру для использования переменной "same"Это конфликт?что же используется в proc use ()?

Ответы [ 3 ]

4 голосов
/ 20 февраля 2012

Из вашего вопроса (и комментариев к Доналу) следует, что вы считаете, что файлы имеют какое-либо отношение к пространствам имен.Эта мысль неверна.

a.tcl

variable same "hello a" ;# global namespace

b.tcl

variable same "hello b" ;# global namespace
proc use {} {
    variable same ;# reads from the global namespace
    puts $same    ;# will puts "hello a" or "hello b" depending on whether
                  ;# a.tcl is sourced after b.tcl or not
}

c.tcl

namespace eval ::not_the_global {
    variable same "hello c" ;# a different namespace, and a different variable than
                            ;# the one from the previous two files
}

d.tcl

namespace eval ::not_the_global {
    proc use {} {     ;# a different use proc from the one in b.tcl
        variable same ;# the variable defined in this namespace in c.tcl
        puts $same    ;# will output "hello c" no matter is a.tcl or b.tcl 
                      ;# were sourced
    }
}

Мораль этой истории в том, что файл, в котором находится код, не имеет отношения к пространствам имен или чему-либо еще.Чтобы команда или переменная находились в отдельном пространстве имен, она должна быть явно размещена там.

3 голосов
/ 20 февраля 2012

Процедура use будет находиться в том же пространстве имен, что и переменная same (файл, в котором находится код, на 100% ортогонален тому, в каком пространстве имен он создает команды и переменные). Однако , тело use не будет иметь доступа к переменным пространства имен по умолчанию, потому что все объявленные процедурой переменные являются локальными переменными по умолчанию. Это означает, что для получения доступа к same вы должны ввести его в область действия с помощью variable, возможно, без аргумента инициализации значения:

proc use {} {
    variable same
    puts $same
}

Вы также можете напрямую использовать полное имя переменной, но это, как правило, медленнее (особенно в цикле).


Прежде чем вы спросите, я ожидаю, что приведенный выше код заставит use напечатать либо «hello1» или «hello2», в зависимости от того, какие порядки a.tcl и b.tcl равны source d. Любое пространство имен должно быть сделано явно через namespace eval ::someNsName { ...script... }. Вы, вероятно, поместите такую ​​вещь вокруг остального содержимого каждого из ваших файлов скриптов. Писать код, который чрезмерно зависит от порядка исходных файлов, обычно считается дурным тоном, в основном потому, что его отладка намного сложнее…

1 голос
/ 21 февраля 2012

Забудьте о двух файлах на мгновение.Предположим, у вас есть только один файл с содержимым:

variable x hello ;# this is a global variable.

proc use {} {
  puts $x
}

Это должно привести к ошибке, которая говорит, что что-то вроде $x не определено.Зачем?Потому что Tcl, в отличие от C, не импортирует ничего в функцию, к которой вы не обращаетесь.Позвольте мне еще раз повторить: tcl procs не видит глобальные переменные или переменные пространства имен, которые вы не указываете на это.

Итак, для импорта глобальных переменных традиционным способом является использование команды global:

variable x hello

proc use {} {
  global x ;# import $x into this proc
  puts $x
}

это должно работать.

Конечно же, для пространств имен слово global не имеет смысла, поэтому была создана команда variable, чтобы позволить процессорам, определенным в пространстве имен, видетьПеременные пространства имен:

namespace eval foo {
  variable x hello

  proc use {} {
    variable x ;# import $x into this proc
    puts $x
  }
}

Существует также другой способ импорта глобальных переменных и переменных пространства имен без явного использования global или variable: просто укажите полное пространство имен.Глобальное пространство имен - просто ::, поэтому также работает следующее:

variable x hello

proc use {} {
  puts $::x
}

и, конечно,

namespace eval foo {
  variable x hello

  proc use {} {
    puts $foo::x
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...