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"
}
在第一个打印MATCH ONE. 1 + one is 2
。在第二个打印MATCH $z. 1 + ONE is 2
。我不明白为什么。
首先,我认为第一个"$z"
位于{}
,所以它被解释为"$z"
,第二个"$z"
不在{}
所以它被解释为"ONE"
。
但我尝试在ONE的第一个开关中打印"$z"
,就像这样
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"
}
}
我发现"$z"
打印为ONE
所以"$z"
"ONE"
的结果与第一个ONE
的结果不一样?谁能帮我回答这个问题?
答案 0 :(得分:2)
如果您在list
命令前加上相对容易看到发生了什么:
% 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"
}
}
第二种形式:
% 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"
}
正如您所看到的,它是阻止$z
扩展到" ONE"。
但是,你说,当你把$z
放在第二个句子中时:
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"
}
}
它打印为" ONE"。嗯,这是因为当选择了第二个子句时,它的代码部分(仅在它已被选中之后)才会在封闭的上下文中进行评估,即与评估switch
的级别相同。
如果我们进一步简化:
switch $x {$z {puts a$z} ONE {puts b$z}}
在这里,switch
获得两个文字参数ONE
和$z {puts a$z} ONE {puts b$z}
(对于后者,这是字面意思"美元符号,z,空白,开括号&#34 ; ...它只是没有特殊含义的文本。)
在switch
内,第二个参数具有一些含义:它现在是标签和脚本的列表(但脚本仍然只是字符串)。评估所有内容的逻辑类似于"如果ONE等于' dollar-sign + z',则评估脚本{puts a $ z}在上层;否则如果ONE等于ONE,则在上层评估脚本{puts b $ z}"。
评估上层的puts b$z
打印" bONE",因为我们现在回到$z
被理解为变量替换而不是字符串美元符号的上下文中+ Z
有一些方法可以处理switch
标签中的变量替换,最简单的方法是使用switch
命令的第二种形式而不用括号列表中的大括号。另一种方法是使用if
- elseif
链。
答案 1 :(得分:0)
问题在于,switch
以大括号形式处理大括号部分的内容作为Tcl列表而不是根据完整的Tcl脚本规则,并且禁用$
和[…]
替换的处理。 (当然,列表中的一些元素然后被解释为脚本,但这是解析的内层。)在第二种形式中,可以使用完整的Tcl替换,因此"$z"
不会扩展为只有一美元和z
,而是读取变量。
大多数情况下,switch
编辑的值是常量(脚本也是如此),大支撑形式是理想的;它(在我看来)也更容易写。但是,在需要复杂替代的情况下,另一种形式更合适。这就是为什么它存在的原因。从理论上讲,您可以使用list
建立一个列表并使用如下所示,但我认为这是非常难看的代码:
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"
}
]
使用具有尽可能多文字的表单有一些性能奖励。特别是,如果所有“模式”都可以在字节码编译时确定为文字(并且所有主体都是文字,并且使用完全匹配 - 使用默认样式),那么switch
是转换成跳转表,一旦你得到合理数量的条款,这些都很快。对于非恒定模式(或非精确匹配),每个模式必须按顺序进行测试;没有切实可行的方法来提高我所知道的效率。