TCL命名空间中的变量

时间:2012-02-20 09:04:03

标签: variables namespaces tcl

我对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()中使用了哪个?

3 个答案:

答案 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
  }
}

还有另一种方法可以导入全局变量和命名空间变量,而无需显式使用globalvariable:只需指定完整的命名空间。全局命名空间只是::,因此以下也适用:

variable x hello

proc use {} {
  puts $::x
}

当然:

namespace eval foo {
  variable x hello

  proc use {} {
    puts $foo::x
  }
}