简体   繁体   English

Tcl大括号内的变量替换

[英]Variable substitution within braces in Tcl

Correct me wherever I am wrong. 纠正我哪里有错。

When we use the variables inside braces, the value won't be replaced during evaluation and simply passed on as an argument to the procedure/command. 当我们在花括号内使用变量时,该值在评估期间不会被替换,而只是作为参数传递给过程/命令。 (Yes, some exception are there like expr {$x+$y} ). (是的,那里有些例外,例如expr {$x+$y} )。

Consider the following scenarios, 考虑以下情况,

Scenario 1 场景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

Scenario 2 方案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
%

In both of the scenarios, we can see that the variable substitution is performed on the body of the if loop (ie {puts "value is $a"} ), whereas in the uplevel , it is not (ie {set val $c} ), based on the current context. 在这两种情况下,我们都可以看到,变量替换是在if循环的主体上执行的(即{puts "value is $a"} ),而在上uplevel ,则不是(例如{set val $c} ),基于当前上下文。

I can see it as if like they might have access it via upvar kind of stuffs may be. 我可以看到它好像他们可以通过upvar类的东西访问它upvar But, why it has to be different among places ? 但是,为什么地方之间必须有所不同? Behind the scene, why it has to be designed in such this way ? 在幕后,为什么必须采用这种方式进行设计? Or is it just a conventional way how Tcl works? 还是仅仅是传统的Tcl工作方式?

Tcl always works exactly the same way with exactly one level of interpretation, though there are some cases where there is a second level because a command specifically requests it. 尽管在某些情况下存在第二级,因为命令明确要求使用第二级,但Tcl始终以完全相同的方式进行完全相同的解释。 The way it works is that stuff inside braces is never interpolated or checked for word boundaries (provided those braces start at the start of a “word”), stuff in double quotes is interpolated but not parsed for word boundaries (provided they start a word), and otherwise both interpolation and word boundary scanning are done (with the results of interpolation not scanned). 它的工作方式是在大括号的东西是永远不会插入或单词边界检查(提供的括号在一个“字”开始启动),东西在双引号内插,但不会被解析为单词边界(只要它们开始一个字),否则将同时执行内插和单词边界扫描( 扫描内插结果)。

But some commands send the resulting word through again. 但是有些命令会再次发送结果字。 For example: 例如:

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

The rule applies to the outer eval , but that concatenates its arguments and then sends the results into Tcl again. 该规则适用于外部eval ,但是它将其参数连接起来,然后将结果再次发送到Tcl。 if does something similar with its body script except there's no concatenation, and instead there's conditional execution. if与它的主体脚本有相似之处,除了没有串联,而是有条件执行。 proc also does the same, except it delays running the code until you call the procedure. proc也做同样的事情,除了它会延迟运行代码直到您调用该过程为止。 The expr command is like eval , except that sends the script into the expression evaluation engine, which is really a separate little language. expr命令类似于eval ,只是将脚本发送到表达式评估引擎中,这实际上是一种单独的小语言。 The if command also uses the expression engine (as do while and for ). if命令还使用表达式引擎(与whilefor )。 The expression language understands $var (and […] ) as well. 表达式语言也可以理解$var (和[…] )。

So what happens if you do this? 那么,如果执行此操作会怎样?

set x [expr $x + $y]

Well, first we parse the first word out, set , then x , then with the third word we start a command substitution, which recursively enters the parser until the matching ] is found. 好吧,首先我们解析出第一个单词set ,然后x ,然后与第三个单词一起开始命令替换,该命令替换将递归地进入解析器,直到找到匹配的] With the inner expr , we first parse expr , then $x (reading the x variable), then + , then $y . 使用内部expr ,我们首先解析expr ,然后解析$x (读取x变量),然后解析+ ,然后解析$y Now the expr command is invoked with three arguments; 现在,使用三个参数调用expr命令。 it concatenates the values with spaces between them and sends the result of the concatenation into the expression engine. 它将值之间用空格连接起来,然后将连接的结果发送到表达式引擎中。 If you had x previously containing $ab and y containing [kaboom] , the expression to evaluate will be actually: 如果您以前有x包含$aby包含[kaboom][kaboom]计算的表达式实际上是:

$ab + [kaboom]

which will probably give you an error about a non-existing variable or command. 这可能会给您有关不存在的变量或命令的错误。 On the other hand, if you did expr {$x + $y} with the braces , you'll get an addition applied to the contents of the two variables (still an error in this case, because neither looks like a number). 另一方面,如果使用大括号 expr {$x + $y} ,则会对两个变量的内容加上加法(在这种情况下仍然是错误的,因为两者看起来都不像数字)。


You're recommended to brace your expressions because then the expression that you write is the expression that will be evaluated. 建议您将表达式括起来,因为编写的表达式就是要计算的表达式。 Otherwise, you can get all sorts of “unexpected” behaviours. 否则,您将获得各种各样的“意外”行为。 Here's a mild example: 这是一个温和的示例:

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

Remember, Tcl always works the same way. 记住,Tcl总是以相同的方式工作。 No special cases. 没有特殊情况。 Anything that looks like a special cases is just a command that implements a little language (often by calling recursively back into Tcl or the expression engine). 看起来像是特例的任何东西都只是一种实现某种语言的命令(通常是通过递归地调用Tcl或表达式引擎)。

In addition to Donal Fellows's answer: 除了Donal Fellows的答案之外:

In scenario 2, in x the command uplevel {set val $c} is invoked, and fails because there is no such variable at the caller's level. 在方案2中,在x ,调用命令uplevel {set val $c} ,但失败,因为在调用者级别没有这样的变量。

In y , the equivalent of uplevel {set val 10} is invoked (because the value of c is substituted when the command is interpreted). y ,将调用uplevel {set val 10}的等效项(因为在解释命令时将替换c的值)。 This script can be evaluated at the caller's level since it doesn't depend on any variables there. 该脚本可以在调用者级别进行评估,因为它不依赖于那里的任何变量。 Instead, it creates the variable val at that level. 而是在该级别创建变量val

It has been designed this way because it gives the programmer more choices. 之所以这样设计,是因为它为程序员提供了更多选择。 If we want to avoid evaluation when a command is prepared for execution (knowing that the command we invoke may still evaluate our variables as it executes), we brace our arguments. 如果要在准备执行命令时避免求值(知道我们调用的命令在执行时仍可以求值),则应加括号。 If we want evaluation to happend during command preparation, we use double quotes (or no form of quoting). 如果我们希望在命令准备期间进行评估,则可以使用双引号(或不使用任何形式的引号)。

Now try this: 现在尝试这个:

% set c 30
30
% x
30
% y
10

If there is such a variable at the caller's level, x is a useful command for setting the variable val to the value of c , while y is a useful command for setting the variable val to the value encapsulated inside y . 如果在呼叫方的电平这样的变量, x是用于设定变量的有用命令val到的值c ,而y是用于设定变量的有用命令val包封内的值y

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM