命名空间的存在是为了对两个可能引起混淆的东西进行分类以示区别。
常见的情况之一,比如某个变量名字,大家都很喜欢用,可又不希望彼此影响,就可以用命名空间进行区分。命名空间本质上是给事物限定一个范围。比如城市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 $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 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 在 Tcl 中常被用来表示库(library)或包(package)。通过 namespace import 把别的库中的命令导入到当前空间,从而可以直接使用相关命令,而无需再添加命名空间前缀。
return [namespace code {cmd_a}]
简单用法如下:
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
导出命令