名字空间
名字空间为命令和变量提供了新的作用域。一个名字空间就是一个变量和命令的集合。名字空间将变量和命令/过程封装起来以避免和其他名字空间的变量和命令冲突。 Tcl 始终有一个默认的名字空间,我们称之为全局名字空间。全局名字空间包含了所有全局变量和命令。
1. 创建名字空间
使用 namespace eval 命令可以让你创建新的名字空间。其语法为:
- namespace eval spaceName { body }
定义名字空间 Counter示例:
namespace eval Counter {
namespace export bump
variable num 0
proc bump {} {
variable num
return [incr num]
}
}
上例创建了一个含有变量 num 和过程 bump 的名字空间 Counter。名字空间中的变量和命令与同一程序中的相同名字的变量和命令相隔离。例如在全局名字空间中也有一个 bump 过程的话,它与 Counter 内的 bump 被认为是不同的过程,可以分别使用。
名字空间的定义是动态的,你可以在需要的时候对名字空间的内容进行更改,也同样是使用namespace eval 命令。如下面的两个命令和上面的名字空间定义命令效果相同(过程 test 首先被添加到名字空间,然后第二次的时候用 rename 将其删除):
namespace eval Counter {
variable num
proc test{args} {
return $args
}
}
namespace eval Counter {
namespace export bump #两个bump不属于同一个过程
proc bump {} {
variable num
return [incr num]
}
rename test ""
}
2. 用::限定符来使用变量和过程
可以使用限定符::来使用名字空间的变量和过程。如:
Counter::test 就可以调用名字空间 Counter 的过程 test,而$Counter::num 引用Counter 中的变量 num。
对于使用全局变量和过程,可以有两种方法,一种是用 global 声明,另一种是用限定符::引导全局变量和过程,如::num 则引用全局变量 num,用$::num 来获得其值。
直接以::作为前导的名字我们称之为“全限定名”,它指明在全局名字空间中对其进行解析。而没有::作为前导的名字为“部分限定名”,它指明从当前的名字空间中对其进行解析。如:
- ::foo::x
表明 x 属于 foo 为全局名字空间的名字空间,而
- foo::x
表明 x 属于 foo 为当前名字空间(不一定是全局名字空间)的名字空间。
namespace eval foo {
namespace eval foo {
proc test {} {
puts "In ::foo::foo::test"
}
}
proc test {} {
puts "Enter ::foo:test"
puts "Call ::foo::foo::test"
foo::test #调用::foo::foo::test
puts "End ::foo:test"
}
foo::test #调用::foo::foo::test
::foo::test #调用::foo::test
}
=> In ::foo::foo::test
Enter ::foo:test
Call ::foo::foo::test
In ::foo::foo::test
End ::foo:test
3. 名字空间的变量
名字空间中的变量用 variable 定义,它类似与全局变量,名字空间中的过程要使用variable 命令可以使用名字空间的变量。
语法:
- variable name ?value? ?name value ? ?... name value?
可以用 variable 先声明变量而将赋值操作留到后面。但如果先声明而在不赋值情况下引用变量的话,会出错。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端