TCL中switch有两种结构。
switch ?options? string pattern body ?pattern body ...?
switch ?options? string {pattern body ?pattern body ...?}
第一种和第二种之间的差别仅仅是一对大括号。正是由于这个区别,应用是要特别注意,否则程序无法输出正确结果。
第一次使用switch时我写了下面这段程序。
switch $cmd {
$::CMD_REPEAT { set cmdInt $::REPEAT }
$::CMD_MATCH { set cmdInt $::MATCH }
$::CMD_MATCH_END { set cmdInt $::MATCH_END }
$::CMD_CALL { set cmdInt $::CALL }
$::CMD_RETURN { set cmdInt $::RETURN }
$::CMD_LOOP { set cmdInt $::LOOP }
$::CMD_LOOP_END { set cmdInt $::LOOP_END }
default { set cmdInt 0 }
}
这段程序在一个名字为bin的proc中,其中引用的变量(如CMD_REPEAT、REPEAT等等)定义在另一个tcl中,所以使用了$::。程序看似正确,但是当我调用时却无法输出正确结果。
set command "REPEAT"
source hex2bin.tcl
bin $command
command是在调用bin过程时传入的参数。在proc bin中将$command与另一个tcl文件中定义的CMD_REPEAT等字符串进行对比。在另一个tcl文件中,CMD_REPEAT定义为"REPEAT",REPEAT被定义为1。command的值是"REPEAT",和CMD_REPEAT的值是相同的。但是该proc执行时,每次都进入default中,其他条件始终不满足。
解决这个问题花费了挺长时间,后来定位在switch的大括号上。由于使用了大括号,其内部内容视为一个整体。且由于{}内的内容不会被转码,所以第一个条件实际上是$::CMD_REPEAT本身,TCL不会对其进行变量替换。为了解决该问题,采用第一种方法使用switch即可。如以下代码。
switch $cmd \
$::CMD_REPEAT { set cmdInt $::REPEAT } \
$::CMD_MATCH { set cmdInt $::MATCH } \
$::CMD_MATCH_END { set cmdInt $::MATCH_END } \
$::CMD_CALL { set cmdInt $::CALL } \
$::CMD_RETURN { set cmdInt $::RETURN } \
$::CMD_LOOP { set cmdInt $::LOOP } \
$::CMD_LOOP_END { set cmdInt $::LOOP_END } \
default { set cmdInt 0 }
由于去掉了switch后的大括号,$::CMD_REPEAT会正常进行变量替换,变成字符串"REPEAT"。此时$command的值才会和$::CMD_REPEAT一致。只是第一种方法书写不太方便,需要在除最后一行外,每一行末尾都需要加上一个“\”,以表示该行尚未结束。