0

在我错的地方纠正我。

当我们在大括号内使用变量时,该值不会在评估期间被替换,而是简单地作为参数传递给过程/命令。(是的,有一些例外,例如expr {$x+$y})。

考虑以下场景,

方案 1

% set a 10
10
%  if {$a==10} {puts "value is $a"}
value is 10
%  if "$a==10" "puts \"value is $a\""
value is 10

方案 2

%  proc x {} {
        set c 10
        uplevel {set val $c}
}
%
% proc y {} {
         set c 10
        uplevel "set val $c"
}
% x
can't read "c": no such variable
% y
10
% set val
10
%

在这两种情况下,我们都可以看到变量替换是在if循环体(即{puts "value is $a"})上执行的,而在循环体中uplevel,它不是(即{set val $c}),基于当前上下文。

我可以看到它好像他们可以通过upvar某种东西访问它。但是,为什么它必须在不同的地方不同?在幕后,为什么要这样设计?或者它只是一种传统的工作方式Tcl

4

2 回答 2

3

Tcl 总是以完全相同的方式工作,只有一个解释级别,尽管在某些情况下存在第二个级别,因为命令专门请求它。它的工作方式是大括号内的内容永远不会被插入或检查单词边界(假设这些大括号从“单词”的开头开始),双引号中的内容被插入但不解析单词边界(前提是它们开始一个单词),否则将完成插值和字边界扫描(扫描插值结果)。

但是有些命令会再次发送结果字。例如:

eval {
    puts "this is an example with your path: $env(PATH)"
}

该规则适用于 external eval,但它连接了它的参数,然后再次将结果发送到 Tcl。if除了没有连接之外,它的主体脚本做了类似的事情,而是有条件执行。proc也这样做,只是它会延迟运行代码,直到您调用该过程。该expr命令类似于eval,只是将脚本发送到表达式评估引擎,这实际上是一种单独的小语言。该if命令还使用表达式引擎(如 dowhilefor)。表达式语言也能理解$var(and […])。

那么如果你这样做会发生什么?

set x [expr $x + $y]

好吧,首先我们解析出第一个单词set,然后x是,然后用第三个单词开始一个命令替换,它递归地进入解析器,直到找到匹配]项。使用 inner expr,我们首先解析expr,然后$x(读取x变量),然后+,然后$y。现在expr使用三个参数调用该命令;它将值与它们之间的空格连接起来,并将连接的结果发送到表达式引擎。如果您x以前包含$aby包含[kaboom],则要评估的表达式实际上是:

$ab + [kaboom]

这可能会给你一个关于不存在的变量或命令的错误。另一方面,如果你expr {$x + $y} 使用了大括号,你会得到一个应用于两个变量内容的加法(在这种情况下仍然是一个错误,因为它们看起来都不像一个数字)。


建议您用括号括起来,因为这样您编写的表达式就是将被评估的表达式。否则,您可能会得到各种“意外”行为。这是一个温和的例子:

set x {12 + 34}
puts [expr $x]
set y {56 + 78}
puts [expr $y]
puts [expr $x * $y]

请记住,Tcl 总是以相同的方式工作。没有特殊情况。任何看起来像特殊情况的东西都只是实现了一种小语言的命令(通常通过递归调用回 Tcl 或表达式引擎)。

于 2016-05-18T13:47:29.533 回答
0

除了Donal Fellows的回答:

在场景 2 中,inx命令uplevel {set val $c}被调用,但由于调用者级别没有这样的变量而失败。

在中,调用y等效的(因为在解释命令时替换了 的值)。该脚本可以在调用者级别进行评估,因为它不依赖于那里的任何变量。相反,它会在该级别创建变量。uplevel {set val 10}cval

之所以这样设计,是因为它为程序员提供了更多选择。如果我们想在准备执行命令时避免评估(知道我们调用的命令可能在执行时仍然评估我们的变量),我们支持我们的参数。如果我们希望在命令准备期间进行评估,我们使用双引号(或不使用引号)。

现在试试这个:

% set c 30
30
% x
30
% y
10

如果在调用者级别存在这样的变量,则将x变量设置val为 的值是一个有用的命令c,而将变量设置为封装在里面的值是一个有用的命令。yvaly

于 2016-05-18T18:45:10.777 回答