2

Tcl 手册说花括号不允许变量替换。但是,这仅适用于某些命令,但不适用于其他命令。

有什么区别以及如何识别将发生替换的情况和不会发生替换的情况?

% set x 3
3
% puts {$x}
$x
% expr {$x}
3
4

2 回答 2

3

参考标准命令列表:任何带有“正文”或“脚本”参数的命令最终都会将该正文评估为代码。不保证详尽无遗:

after, apply, catch, eval, expr, fileevent(and chan 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
于 2019-08-18T23:04:04.400 回答
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
于 2019-08-19T13:31:23.137 回答