Команда return
концептуально вызывает исключение (типа return
, которое соответствует коду результата TCL_RETURN
в Tcl C API), которое перехватывается процедурой (строго, оболочкой процедуры, которая делает вещи как управление callframe и сортировка аргументов), в котором он работает, чтобы заставить что-то делать. В случае обычного return
он просто заставляет процедуру возвращать это значение, но когда предоставляется опция -code
, он может направить процедуру на выполнение чего-то другого; это делается после извлечение callframe из стека вызовов Tcl.
Поскольку 2
является фактическим значением кода результата TCL_RETURN
, это означает, что он говорит оболочке процедуры (т. Е. Общей процедуре Z
) вести себя так, как будто это был простой вызов return
именно поэтому puts "Y - out"
не выполняется; есть исключение возврата, обрабатываемое в результате выполнения Z
. (FWIW, return -code 2
встречается довольно редко. return -code 1
/ return -code error
встречается гораздо чаще, так как это способ получения исключения error , которое полезно, потому что трассировки стека только построено на исключениях ошибок.)
Вы можете переопределить эту обработку, используя catch
или try
. Немного проще сделать это правильно с try
, так как catch
является довольно широким примитивом. Попробуйте это:
proc Y {} {
puts "Y - in"
try {
Z
} on return {msg} {
puts "Z told us to return '$msg'"
}
puts "Y - out"
}
Если вы просто хотите, чтобы короткий фрагмент кода работал после вызова, но в остальном не мешал, try
… finally
- правильный путь:
proc Y {} {
puts "Y - in"
try {
Z
} finally {
puts "Y - out"
}
}
Если вы используете Tcl 8.5 (или раньше), у вас не будет try
. Вот версия с catch
:
proc Y {} {
puts "Y - in"
set code [catch {
Z
} msg]
if {$code == 2} {
puts "Z told us to return '$msg'"
}
puts "Y - out"
}
Проблема с catch
заключается в том, что очень легко потерять ошибки случайно.