如果在交互模式下使用Tcl,我在其中输入以下内容:
set list {1 2 3 4 5}
set sum 0
foreach el $list {
set sum [expr $sum + $element]
}
Run Code Online (Sandbox Code Playgroud)
它会显示一条非常简洁的信息:
can't read "element": no such variable
Run Code Online (Sandbox Code Playgroud)
但是当我用的时候
puts $errorInfo
Run Code Online (Sandbox Code Playgroud)
它将显示:
can't read "element": no such variable
while executing
"expr $sum + $element"
("foreach" body line 2)
invoked from within
"foreach el $list {
set sum [expr $sum + $element]
}"
Run Code Online (Sandbox Code Playgroud)
这就是我真正想要的.
问题是:在非交互模式下,当我想捕获此错误然后放入errorInfo以获得堆栈跟踪时,它只会显示简洁信息.如何获得如上所述的详细堆栈跟踪?非常感谢!
编辑添加更多细节
说我有以下代码:
proc test1 {} {
set list {1 2 3 4 5}
set sum 0
foreach el $list {
if {[catch {set sum [expr $sum + $element]} err]} {
puts $::errorInfo
}
break
}
}
proc test2 {} {
foreach el $list {
set list {1 2 3 4 5}
set sum 0
set sum [expr $sum + $element]
}
}
#test1
#test2
Run Code Online (Sandbox Code Playgroud)
如果我取消注释"#test1",它将显示:
无法读取"元素":
执行
"expr $ sum + $ element"时没有这样的变量
如果我取消注释"#test2",它将显示:
无法读取"元素":
执行"expr $ sum + $ element"
(过程"test2"第5行)
从
"test2"
(文件)中调用时没有这样的变量"./test.tcl"第137行)
我想要的当然是test2行为.如何使用catch显示此错误信息?
您能说明如何以非交互模式捕获/放置信息吗?
如果你这样做了
if {[catch {...your...code...here...} err]} {
puts "Error info $err"
}
Run Code Online (Sandbox Code Playgroud)
然后你所描述的行为是预期的 - $err只有"简洁信息".你可能想要的puts是:
puts "Error info $err\nFull info: $::errorInfo"
Run Code Online (Sandbox Code Playgroud)
如果::在proc或命名空间内调用catch以确保您使用的变量是实际的toplevel :: errorInfo,则需要前缀.
编辑以解决后续问题
正如科林回答的那样,你的堆栈痕迹test1和test2你的位置有所不同,因为你放置了捕获物.让我来说明一下.这是一些链式Tcl过程:
proc one {} {
two
}
proc two {} {
three
}
proc three {} {
four
}
proc four {} {
error "Yup, an error"
}
Run Code Online (Sandbox Code Playgroud)
如果你评价
catch {four}
puts $::errorInfo
Run Code Online (Sandbox Code Playgroud)
您将获得如下所示的堆栈跟踪:
Yup, an error
while executing
"error "Yup, an error""
(procedure "four" line 2)
invoked from within
"four"
Run Code Online (Sandbox Code Playgroud)
这是因为错误发生的位置(内部four)和捕获它的位置之间的堆栈跟踪,只有一个过程调用.
相反,如果您发现错误"更远",就像这样:
catch {one}
puts $::errorInfo
Run Code Online (Sandbox Code Playgroud)
之间的堆栈跟踪catch语句和错误包括特效one,two,three,和four.这导致堆栈跟踪如下:
Yup, an error
while executing
"error "Yup, an error""
(procedure "four" line 2)
invoked from within
"four"
(procedure "three" line 2)
invoked from within
"three"
(procedure "two" line 2)
invoked from within
"two"
(procedure "one" line 2)
invoked from within
"one"
Run Code Online (Sandbox Code Playgroud)
所以...为了匹配你的例子test1,如果你重新定义three如下:
proc three {} {
catch {four}
puts $::errorInfo
}
Run Code Online (Sandbox Code Playgroud)
你评价了
if {[catch {one}]} {
puts "Found an error"
}
Run Code Online (Sandbox Code Playgroud)
你不会看到"发现错误",因为three抓住了错误的主体,并打印了堆栈跟踪.堆栈跟踪仅包含catch语句和错误之间的调用- 这(就像我的第一个示例)仅包含对调用的调用four.
所以,你把你的catch陈述放在哪里很重要.
在相关的说明中,您可以重新抛出错误,如果您愿意,可以保留堆栈跟踪.这是以下新定义three:
proc three {} {
if {[catch {four} err]} {
puts "Caught an error $err, re-throwing"
error $err $::errorInfo
}
}
Run Code Online (Sandbox Code Playgroud)
现在,有了重新抛出的错误,你会看到:
tchsh% catch {one}
Caught an error Yup, an error, re-throwing
1
tclsh% set ::errorInfo
Yup, an error
while executing
"error "Yup, an error""
(procedure "four" line 2)
invoked from within
"four"
(procedure "three" line 2)
invoked from within
"three"
(procedure "two" line 2)
invoked from within
"two"
(procedure "one" line 2)
invoked from within
"one"
Run Code Online (Sandbox Code Playgroud)