Я экспериментировал с ансамблями пространства имен и выполняю упражнение для реализации array foreach
(да, я знаю TIP 421 ).
Я использую массив startsearch / more / nextelement / donesearch.Сейчас я пытаюсь отловить ошибку, которая появляется, когда элементы массива добавляются или удаляются во время поиска: я обнаружил, что не могу отловить эту ошибку в своем коде , но могу отловить ее винтерактивный сеанс.
Вот интерактивный сеанс:
% array set Y {foo bar baz qux}
% set sid [array startsearch Y]
s-1-Y
% set key [array nextelement Y $sid]
foo
% set Y(hello) world
world
% try {
set key [array nextelement Y $sid]
} trap {TCL LOOKUP} {msg e} {puts "$sid has been invalidated\n$e"}
s-1-Y has been invalidated
-code 1 -level 0 -errorstack {INNER {invokeStk1 ::tcl::array::nextelement Y s-1-Y}} -errorcode {TCL LOOKUP ARRAYSEARCH s-1-Y} -errorinfo {couldn't find search "s-1-Y"
while executing
"array nextelement Y $sid"
("try" body line 1)} -errorline 1
%
Все хорошо.Мы можем видеть, что searchId становится недействительным после того, как я добавляю элемент массива, когда идет активный поиск: код ошибки начинается с {TCL LOOKUP ARRAYSEARCH}
Теперь я обертываю это в процедуре и организую его получение, когда язапустите интерактивный tclsh (подробности см. this ).Вот тело моего array foreach
proc:
% info body ::monkeypatches::array_foreach
if {[llength $vars] != 2} {
error {array foreach: "vars" must be a 2 element list}
}
lassign $vars keyVar valueVar
# Using the complicated `upvar 1 $arrayName $arrayName` so that any
# error messages propagate up with the user's array name
upvar 1 $arrayName $arrayName $keyVar key $valueVar value
set sid [array startsearch $arrayName]
while {[array anymore $arrayName $sid]} {
# This doesn't seem to be able to catch the error when the user
# tries to modify the array during a search. Hmm.
try {
set key [array nextelement $arrayName $sid]
} trap {TCL LOOKUP ARRAYSEARCH} {"" e} {
return -options $e "detected attempt to modify the array while iterating"
}
set value [set "${arrayName}($key)"]
uplevel 1 $body
}
array donesearch $arrayName $sid
return
Когда я воспроизводлю шаги, чтобы поймать ошибку, я обнаруживаю, что мой try
не ловит ошибку:
% array set Y {foo bar baz qux}
% array foreach {key val} Y {set Y(hello) world}
couldn't find search "s-1-Y"
Замена конкретного предложения trap
на общее on error
не помогает.Также не используется catch
вместо try
.
Я не понимаю, почему этот процесс не может поймать ошибку.Есть мысли?