【问题标题】:The variable in namespace of TCLTCL命名空间中的变量
【发布时间】:2012-02-20 09:04:02
【问题描述】:

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

【问题讨论】:

    标签: variables namespaces tcl


    【解决方案1】:

    从您的问题(以及对 Donal 的 cmets)看来,您认为文件与命名空间有任何关系。这种想法是错误的。

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

    这个故事的寓意是代码所在的文件与命名空间或其他任何东西无关。对于要在单独的命名空间中的命令或变量,它必须显式地放置在那里。

    【讨论】:

      【解决方案2】:

      use 过程将与same 变量位于同一命名空间中(代码所在的文件与它在其中创建命令和变量的命名空间 100% 正交)。 然而,默认情况下use 的主体将无法访问命名空间的变量,因为所有过程声明的变量默认都是局部变量。这意味着要访问same,您应该使用variable 将其带入范围,可能没有值初始化参数:

      proc use {} {
          variable same
          puts $same
      }
      

      您也可以直接使用变量的完全限定名称,但这往往会更慢(尤其是在循环中)。


      在你问之前,我希望上面的代码会导致use 打印either“hello1”或“hello2”,具体取决于 a.tcl 和 b.tcl 的顺序是 @ 987654328@d。任何命名空间都必须通过namespace eval ::someNsName { ...script... } 显式完成。您可能会在每个脚本文件的其余内容周围放置这样的东西。编写过度依赖源文件顺序的代码通常被认为是一种糟糕的形式,主要是因为它往往更难以调试……

      【讨论】:

      • 你的意思是“使用过程将与同一个变量在同一个命名空间中(代码所在的文件与它在其中创建命令和变量的命名空间 100% 正交)。”?你的意思是:使用程序在a.tcl中看不到相同的变量吗?只能在 b.tcl 中看到相同的内容吗?
      • @ratzip 我的意思是文件和命名空间在它们的机制上完全没有关系。所有source 所做的只是将文件的内容读入一个字符串,然后eval 该字符串。 (嗯,它还设置了info script。一个小的改进。)如果没有在文件中明确写入命名空间,它nothing 。这意味着如果来自相同的上下文,a.tcl 和 b.tcl 看到相同的变量。
      • 此外,作为一种良好做法,最好明确地使用命名空间,这样当您从不同的上下文或以不同的顺序运行代码时,您的代码不会改变行为。你没有必须,但这对你来说更容易......
      • 是的,你说得对,如果不显式写的话跟namespace没有关系,这种情况下,proc use可以看到两个文件中相同的全局变量吗?但是当我们调用 proc use 时,proc use 使用的是哪个变量?
      • @ratzip:如果你不这么说(通过globalupvarvariable),变量将是过程调用的本地变量。
      【解决方案3】:

      暂时忘记这两个文件。假设您只有一个文件,内容是:

      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 命令以允许命名空间中定义的 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
        }
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-06-20
        • 1970-01-01
        • 2014-09-20
        • 1970-01-01
        • 1970-01-01
        • 2014-07-05
        相关资源
        最近更新 更多