“为什么在TCL交换机中?”$z";和一个不一样

“为什么在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 {

在第一个打印<代码>匹配一个。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" {
        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"
    }
]