“为什么在TCL交换机中?”$z";和一个不一样
在第一个打印<代码>匹配一个。1+1等于2。在第二个选项中,打印“为什么在TCL交换机中?”$z";和一个不一样,tcl,Tcl,在第一个打印匹配一个。1+1等于2。在第二个选项中,打印匹配$z。1+1等于2。我不明白为什么 首先,我认为第一个“$z”在{}中,所以它被解释为“$z”,第二个“$z”不在{}中,所以它被解释为“一” 但是我试着在第一个开关中打印“$z”,就像这样 set x "ONE" set y 1 set z ONE # This is probably the easiest and cleanest form of the command # to remember: switch $x {
匹配$z。1+1等于2
。我不明白为什么
首先,我认为第一个“$z”
在{}
中,所以它被解释为“$z”
,第二个“$z”
不在{}
中,所以它被解释为“一”
但是我试着在第一个开关中打印“$z”
,就像这样
set x "ONE"
set y 1
set z ONE
# This is probably the easiest and cleanest form of the command
# to remember:
switch $x {
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
}
ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
TWO {
set y1 [expr {$y+2}]
puts "MATCH TWO. $y + two is $y1"
}
THREE {
set y1 [expr {$y+3}]
puts "MATCH THREE. $y + three is $y1"
}
default {
puts "$x is NOT A MATCH"
}
}
switch $x "$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
} ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
} TWO {
set y1 [expr {$y+2}]
puts "MATCH TWO. $y + two is $y1"
} THREE {
set y1 [expr {$y+3}]
puts "MATCH THREE. $y + three is $y1"
} default {
puts "$x does not match any of these choices"
}
我发现,“$z”
打印为ONE
因此,
“$z”
“ONE”
的结果与第一个中的ONE
的结果不同,哪一个?有人能帮我回答这个问题吗?如果您预先添加列表
命令,则相对容易看到发生了什么:
switch $x {
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
}
ONE {
puts "$z"
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
TWO {
set y1 [expr {$y+2}]
puts "MATCH TWO. $y + two is $y1"
}
THREE {
set y1 [expr {$y+3}]
puts "MATCH THREE. $y + three is $y1"
}
default {
puts "$x is NOT A MATCH"
}
}
结果是:
% list switch $x {
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
}
ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
}
第二种形式:
switch ONE {
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
}
ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
}
正如您所见,正是大括号阻止了$z
扩展为“一”
但是,你说,当你把$z
放在第二个子句中时:
% list switch $x "$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
} ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
switch ONE ONE {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
} ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
它被打印为“一”。这是因为,当第二个子句被选中时,它的代码部分(仅,并且仅在它被选中之后)在封闭上下文中进行计算,即在与开关
计算相同的级别上进行计算
如果我们进一步简化这一点:
switch $x {
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
}
ONE {
puts "$z"
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
}
}
这里,switch
获取两个文本参数,ONE
和$z{put a$z}ONE{put b$z}
(对于后者,这是字面意义上的“美元符号,z,空格,大括号”…它只是没有特殊意义的文本)
在开关中,第二个参数具有某种意义:它现在是标签和脚本的列表(但脚本仍然只是字符串)。计算这一切的逻辑类似于“如果一个等于‘美元符号+z’,则计算脚本{puts a$z}在上层;否则如果一个等于一,则计算脚本{puts b$z}在上层”
计算将b$z
放在上层打印“bONE”,因为我们现在回到了一个上下文中,$z
被理解为变量替换,而不是字符串美元符号+z
有一些方法可以处理switch
标签中的变量替换,最简单的方法是使用switch
命令的第二种形式,在子句列表中不使用大括号。另一种方法是使用if
-elseif
链。问题是,大括号形式的开关将大括号部分的内容作为Tcl列表处理,而不是根据完整的Tcl脚本规则,并且禁用了$
和[…]替换的处理。(当然,列表中的一些元素会被解释为脚本,但这是解析的内层。)在第二种形式中,完整的Tcl替换是可用的,因此,“$z”
不会扩展为仅一美元和一个z
,而是一个变量的读取
大多数情况下,switch
ed对应的值是常量(脚本也是如此),大括号形式是理想的;(在我看来)写起来也比较容易。然而,在需要复杂替换的情况下,另一种形式更合适。这就是它存在的原因。理论上,你可以用list
建立一个列表,并在下面使用它,但我认为这是非常难看的代码:
switch $x {$z {puts a$z} ONE {puts b$z}}
使用具有尽可能多的文本的表单会带来一些性能提升。特别是,如果所有的“模式”都可以在字节码编译时确定为文字(所有的主体都是文字,并且使用了精确匹配(默认样式),那么开关
将转换为跳转表,一旦获得了合理数量的子句,这些转换就会非常快。对于非恒定模式(或非精确匹配),必须按顺序测试每个模式;据我所知,没有切实可行的方法来提高效率。现在是凌晨4:40,我还没有完全清醒。希望这仍然有意义。如果没有,请发表评论,明天我会再看一看。我很惊讶在“默认”块之后没有行连续性的错误。@glennjackman:括号内的文本作为脚本处理:如果有多个命令,可能在命令之前或之后,或在命令之间有换行符。或者,断线可以逃脱,但不一定要逃脱。
switch $x [list \
"$z" {
set y1 [expr {$y+1}]
puts "MATCH \$z. $y + $z is $y1"
} \
ONE {
set y1 [expr {$y+1}]
puts "MATCH ONE. $y + one is $y1"
} \
TWO {
set y1 [expr {$y+2}]
puts "MATCH TWO. $y + two is $y1"
} \
THREE {
set y1 [expr {$y+3}]
puts "MATCH THREE. $y + three is $y1"
} \
default {
puts "$x does not match any of these choices"
}
]