我对TCL命名空间中的变量有疑问。
我有两个.tcl文件,a.tcl,b.tcl,我在这两个文件中定义了相同的全局变量,例如:
a.tcl
variable same "hello1"
b.tcl
variable same "hello2"
proc use {} {
puts same
}
但在b.tcl中,我尝试定义一个proc来使用变量“same
”,这是冲突吗?在proc use()中使用了哪个?
答案 0 :(得分:4)
从您的问题(以及对Donal的评论)中可以看出,您认为文件与命名空间有关。这个想法不正确。
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
}
}
故事的寓意是代码所在的文件与名称空间或其他任何内容无关。要使命令或变量位于单独的命名空间中,必须将其显式放在那里。
答案 1 :(得分:3)
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... }
明确完成。您可能会对每个脚本文件的其余内容进行此类操作。编写过于依赖源文件顺序的代码通常被认为是不好的形式,主要是因为调试起来要困难得多......
答案 2 :(得分:1)
暂时忘记这两个文件。让我们假设你只有一个文件,内容是:
variable x hello ;# this is a global variable.
proc use {} {
puts $x
}
这会导致错误,表明$x
之类的内容未定义。为什么?因为与C不同,Tcl不会将任何内容导入到您不需要它的函数中。让我再说一遍:tcl procs没有看到你没有告诉它的全局或命名空间变量。
因此,要导入全局变量,传统方法是使用global
命令:
variable x hello
proc use {} {
global x ;# import $x into this proc
puts $x
}
这应该有效。
对于名称空间,当然单词global
没有意义,因此创建variable
命令以允许在名称空间中定义的proc查看命名空间变量:
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
}
}