Tcl/Tk Insight: 命名空间 (namespace)

风行水上 @ 2009-06-20 08:52:01
标签:
    «目录»

    命名空间的存在是为了对两个可能引起混淆的东西进行分类以示区别。

    常见的情况之一,比如某个变量名字,大家都很喜欢用,可又不希望彼此影响,就可以用命名空间进行区分。命名空间本质上是给事物限定一个范围。比如城市A的张三和城市B的张三,要是不通过“城市A”和“城市B”这样的范围来加以明确的话,谁知道究竟是指那个张三呢。

    基本用法:

    namespace eval myspace {
        variable var_tmp "haha"
    } ; # 创建一个命名空间(namespace) 
    
    set var_name "value 1"
    set myspace::var_name "value 2"  ; # 通过使用"::"连接空间名字和变量名
    set myspace::var_tmp "haha 2"    ; 
    puts $::var_name                 ; 默认的命名空间为空字符 ""
    
    proc myspace::echo {msg} {
        puts "== $msg"
    }    ; # 函数也可以有不同的命名空间
    
    namespace eval myspace::subspace {} ; # 命名空间可以嵌套
    set myspace::subspace::var_name "value 3"
    

    有了命名空间,就可以使用自己喜欢的变量名或者函数名而不用担心与他人的程序代码冲突了。当然你的命名空间的名字必须是不同于他人的。根据Java里包(package)的命名建议,推荐使用倒序的URI。比如,我可以写

    namespace eval net::noyesno {
       # This is my namespace
       proc echo {msg} { puts "noyesno.net: $msg"}
    }
    

    不过Tcl里面的namespace的功能要强大的多。

    命名空间的创建、删除和查询

    • 创建 namespace eval ::a::b {}
    • 删除 namespace delete ::a::b ::a::c
    • 当前空间 namespace current
    • 是否存在 namespace exists ::a::b
    • 查询子空间。namespace children ?which? ?pattern?
    • 查询父空间。namespace parent ?which?

    命名空间的使用

    namespace eval & namespace inscope

    namespace eval ::a::b $script $x $y $z
    在指定的命名空间中执行命令 $script $x $y $z

    namespace inscope ::a::b $script $x $y $z
    在指定的命名空间中执行命令 $script [list $x $y $z] 。和 namespace eval 很像,只是对第一个参数之后的参数处理不同。主要用于 namespace code,一般不直接使用这条命令。

    两者的区别主要是对参数处理的不同。namespace eval是将所有参数concat起来;namespace insope则先将第一个参数以外的参数绊组成一个list然后再concat。

    namespace eval ::t $script $a $b             ;# 相当于下面concat所有参数
    namespace eval ::t [concat $script $a $b ]   ;# 参数$a和$b的整体性可能会被破坏
    
    namespace inscope ::t $script $a $b          ;#  
    namespace eval ::t $script [list $a $b ]
    namespace eval ::t [concat $script [list $a $b]] ;# 参数$a和$b的整体性得以保全
    
    
    namespace eval    ::t dump 3 {4 5}    ;# dump 3 4 5   第二个参数被降维了
    namespace inscope ::t dump 3 {4 5}    ;# dump 3 {4 5} 第二个参数维持了整体性
    namespace eval    ::t {dump 3 {4 5}}  ;# dump 3 {4 5} 所见即所得
    namespace inscope ::t {dump 3 {4 5}}  ;# dump 3 {4 5} 所见即所得
    

    namespace code & namespace inscope

    返回一个包装好的命令,从而在调用时可以不用指定命名空间。参考下面的例子可以理解。

    namespace eval ::t {
      proc dump { args } { puts [list [llength $args] $args] }
      proc callback {} { return [namespace code {dump 3}]}
    }
    
    set script [::t::callback]
    $script 4 {5 6}                       ;# 作用相当于下面的namespace inscope命令 
    namespace inscope ::t {dump 3} 4 {5 6}    ;# 相当于
    namespace eval ::t [concat {dump 3} [list 4 {5 6}]] 
    namespace eval ::t {dump 3 4 {5 6}]
    
    puts $script ;# 输出 ::namespace inscope ::t {dump 3}
    # namespace code相当于创建了一个“特殊”名称的命令用来执行namespace inscope命令
    

    名字的解析

    • 变量名:先在本命名空间查找,找不到则在全局空间中查找
    • 命令名:先在本命名空间查找,然后是[namespace path]指定的空间(默认为空)中查找,最后是全局空间
      • 最终找不到的话则交由namespace unknown指定的命令(默认是命令::unknown)处理
    • 命名空间名:只在当前空间中查找

    两个 namespace 之间进行命令引用

    • namespace export ?-clear? proc_name_pattern
    • namespace import ?-force? proc_name_pattern
    • namespace forget proc_name_pattern
    • namespace origin proc_name

    namespace 在 Tcl 中常被用来表示库(library)或包(package)。通过 namespace import 把别的库中的命令导入到当前空间,从而可以直接使用相关命令,而无需再添加命名空间前缀。

    命名空间名字的操作

    • namespace qualifiers ::a::b::c ; # 返回 ::a::b
    • namespace tail ::a::b::c ; #返回 c
    • namespace which ?-command? ?-variable? name 查询命令或者变量的完整名称,类似于 shell 命令 which

    命令的导入和导出

    • namespace import $ns:cmd_*
    • namespace export cmd_a cmd_b
    • return [namespace code {cmd_a}]

    namespace ensemble

    简单用法如下:

    namespace eval cell {
      namespace export * ; 
      namespace ensemble create
      proc name {} { return [format "cell_%d" [info cmdcount]] }
      proc bbox {llx lly urx ury} { return [list $llx $lly $urx $ury] }
    }
    
    cell name                  ;# 相当于 namespace eval cell {name}
    cell bbox  100 200 300 400 ;# 相当于 cell::bbox 100 200 300 400
    

    几个关键点:

    • namespace ensemble create 命令
    • namespace export 导出命令
    标签:

      分享到:
      comments powered by Disqus

      29/33ms