有没有一种简单的方法可以在 Tcl 中展开堆栈?我有一个奇怪的问题,我必须回到一个特定的堆栈帧,字面意思。我可以使用info
命令获取所有帧信息,但要实际获取特定帧,我必须在每个过程中设置一些局部变量并相应地检查它们。我想知道是否有更简单的方法。
3 回答
如果您需要获取代码来执行非本地返回(即,跳过几个级别),您可以从 8.5 开始-level
使用return
. 看这个例子:
proc foo-a {} {
puts a-in
foo-b
puts a-out
}
proc foo-b {} {
puts b-in
foo-c
puts b-out
}
proc foo-c {} {
puts c-in
foo-d
puts c-out
}
proc foo-d {} {
puts d-in
bar
puts d-out
}
proc bar {} {
puts bar-in
return -level 3
puts bar-out
}
foo-a
这是通过抛出一种特殊的异常来实现的;细节相当隐蔽。或者,如果您有 8.6 或它们的脚本实现,您也可以使用try
(throw
请参阅Tcler 的 Wiki,了解在讨论 8.6 中的代码期间使用的 Tcl 代码)。
对于较旧的 Tcl 版本,最简单的机制是使用return -code 42
并将一些代码放置catch
在自定义异常的堆栈上,并确定它是否是魔法值(这里是 42;它将是 的结果catch
)并适当地响应。这可能非常有效,但也很混乱。这就是为什么 8.5 及更高版本为您提供更易于使用的工具的原因。
简短的回答是你可能会更好地重新考虑你的设计。
更长的答案是,唯一真正的方法(我能想到的)是抛出一个错误并将其重新捕获到您需要停止它的级别。当然,除了在调用堆栈中一直检查变量的不那么火爆的方式。然而,对控制流使用错误是……不好的形式。
如果您愿意成为最前沿的人,协程(在 8.6 中可用)可能会满足您的需求。
否则,您可能会尝试记录您在那里时需要达到的例程级别(即,将全局变量设置为 [info level]),然后在更深的 proc 中,[uplevel] 到那个绝对堆栈帧。就像是
proc need-to-be-here {} {
set ::myframe [info level]
deeper-calls
}
proc deepest-call {} {
uplevel #$::myframe {what I need to do}
}
(未经测试)