在 tcl 中打破超过 1 级的 foreach 嵌套
break more than 1 level of foreach nesting in tcl
是否可以从两层嵌套中在 1 个命令中退出?也就是说,假设我有这个代码:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
break2
} else {
puts "$k $l"
}
}
我希望看到的输出是:
1 3
1 4
问题是,如何编写 break2(如果可能的话)?
除了将其包装在 proc 中之外,我不知道任何语言都有这样的 "feature",并且使用 return 停止进程,这比正确的语言结构更像是一种技巧
谢谢。
在 Tcl ≥ 8.5 中是可能的:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if {$k > 4} {
return -code break -level 2
} else {
puts "$k $l"
}
}
}
return -code break -level 2
的工作方式类似于 "make the enclosing command two levels up the stack return as if it has called break
"。
直接做是不行的; break
机器除了最近的循环上下文之外没有任何东西可以追踪到任何东西。
处理此问题的最简单方法是在 8.6 中使用 try
和自定义异常代码(即 5 以上的任何值)。
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
try {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
# Generating a custom exception code is a bit messy
return -level 0 -code 5
}
puts "$k $l"
}
}
} on 5 {} {
# Do nothing here; we've broken out
}
}
运行 给出了这个输出:
a=b; to show that this is not stopping the outermost loop
3 1
4 1
a=c; to show that this is not stopping the outermost loop
3 1
4 1
但是这样做很麻烦;最好的方法通常是重构您的代码,以便您通常可以 return
结束循环。使用 apply
可能会使这更容易:
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
apply {{} {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
return
}
puts "$k $l"
}
}
}}
}
使用 apply
的缺点是它是一个不同的变量上下文并且有相当多的开销(因为所有堆栈帧管理)。不过,如果您小心的话,可以使用 upvar
来解决变量上下文的问题。
是否可以从两层嵌套中在 1 个命令中退出?也就是说,假设我有这个代码:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
break2
} else {
puts "$k $l"
}
}
我希望看到的输出是:
1 3
1 4
问题是,如何编写 break2(如果可能的话)?
除了将其包装在 proc 中之外,我不知道任何语言都有这样的 "feature",并且使用 return 停止进程,这比正确的语言结构更像是一种技巧
谢谢。
在 Tcl ≥ 8.5 中是可能的:
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if {$k > 4} {
return -code break -level 2
} else {
puts "$k $l"
}
}
}
return -code break -level 2
的工作方式类似于 "make the enclosing command two levels up the stack return as if it has called break
"。
直接做是不行的; break
机器除了最近的循环上下文之外没有任何东西可以追踪到任何东西。
处理此问题的最简单方法是在 8.6 中使用 try
和自定义异常代码(即 5 以上的任何值)。
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
try {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
# Generating a custom exception code is a bit messy
return -level 0 -code 5
}
puts "$k $l"
}
}
} on 5 {} {
# Do nothing here; we've broken out
}
}
运行 给出了这个输出:
a=b; to show that this is not stopping the outermost loop 3 1 4 1 a=c; to show that this is not stopping the outermost loop 3 1 4 1
但是这样做很麻烦;最好的方法通常是重构您的代码,以便您通常可以 return
结束循环。使用 apply
可能会使这更容易:
foreach a {b c} {
puts "a=$a; to show that this is not stopping the outermost loop"
apply {{} {
foreach l { 1 2 3 4 } {
foreach k { 3 4 5 6 } {
if { $k > 4 } {
return
}
puts "$k $l"
}
}
}}
}
使用 apply
的缺点是它是一个不同的变量上下文并且有相当多的开销(因为所有堆栈帧管理)。不过,如果您小心的话,可以使用 upvar
来解决变量上下文的问题。