Tcl 手册说花括号不允许变量替换。但是,这仅适用于某些命令,但不适用于其他命令。
有什么区别以及如何识别将发生替换的情况和不会发生替换的情况?
% set x 3
3
% puts {$x}
$x
% expr {$x}
3
参考标准命令列表:任何带有“正文”或“脚本”参数的命令最终都会将该正文评估为代码。不保证详尽无遗:
after
,apply
,catch
,eval
,expr
,fileevent
(andchan event
),for
,foreach
,if
,interp eval
,lmap
, 一些namespace
子命令, 一些oo::*
命令,proc
,subst
,switch
,try
,uplevel
,while
这确实是 Tcl 最大的优势之一。它使您能够轻松编写自己的控制结构。例如,Tcl 不提供 do-while 循环,但您可以这样做:
proc do {body while condition} {
if {$while ni {while until}} {
error "some message about usage..."
}
while true {
uplevel 1 $body
set status [uplevel 1 [list expr $condition]]
if {$while eq "while" && !$status} then break
if {$while eq "until" && $status} then break
}
}
以便
% set i 0; while {[incr i] < 3} {puts "$i"}
1
2
% set i 0; do {puts "$i"} while {[incr i] < 3}
0
1
2
% set i 0; do {puts "$i"} until {[incr i] == 3}
0
1
2
一些命令被明确描述为将一个或多个参数视为脚本或表达式;当脚本或表达式的评估发生时(可能是立即的,也可能是稍后的,具体取决于命令),在作为脚本或表达式的字符串中描述的替换被执行。(该subst
命令是一种特殊情况,只能应用选定的替换子集。)
你怎么知道哪个是哪个?这取决于命令。字面上地。去阅读文档。例如,在我们看到的文档中:catch
概要
捕捉 脚本?结果变量名?? 选项变量名?
描述
catch命令可用于防止错误中止命令解释。catch命令以递归方式调用 Tcl 解释器来执行script ,并且无论在执行script时可能发生的任何错误,它总是返回而不引发错误。[…]
在这种情况下,我们看到第一个参数总是(立即)通过调用 Tcl 解释器作为 Tcl 脚本进行评估(或者更确切地说,在大多数情况下它实际上是编译的字节码,但这是一个实现细节)。
同样,在文档中proc
我们看到:
概要
proc 名称 args 正文
描述
proc命令创建一个名为name的新 Tcl 过程,用该名称替换任何现有的命令或过程。每当调用新命令时,body的内容将由 Tcl 解释器执行。[…]
在这种情况下,主体将被评估为脚本(“由 Tcl 解释器”是一种语言形式),但稍后在调用过程时。(catch
对此只字未提;暗示它立即行动。)
第三种情况是文档while
:
概要
同时 测试身体
描述
while命令将test作为表达式求值(与expr求值其参数的方式相同)。表达式的值必须是适当的布尔值;如果它是一个真值,那么body通过将它传递给 Tcl 解释器来执行。[…]
由此,我们可以看到test参数是一个表达式(它使用表达式规则),而body是一个脚本。
如果您想创建一个无需替换的单命令脚本,您可以在其中对所有内容使用任意值(这非常适合设置回调),请使用list
定义为以规范形式生成列表的命令,这会发生(按设计)正是没有替代惊喜的单个命令可以采用的形式:
set xyz "123 456"
set callback [list puts $xyz]
set xyz {[crash bang wallop]}
puts "READY..."
eval $callback