`массив nextelement` - не может отловить ошибку, когда searchId был признан недействительным - PullRequest
0 голосов
/ 20 ноября 2018

Я экспериментировал с ансамблями пространства имен и выполняю упражнение для реализации 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.

Я не понимаю, почему этот процесс не может поймать ошибку.Есть мысли?

1 Ответ

0 голосов
/ 20 ноября 2018

Если вы посмотрите на трассировку ошибок, вы увидите, что ошибка не идет от того места, где вы ожидаете.(Я создал процедуру как array_foreach для целей этого теста.)

% array_foreach {x y} tcl_platform {set tcl_platform(foo) bar;puts $x->$y}
osVersion->16.7.0
couldn't find search "s-1-tcl_platform"
% set errorInfo
couldn't find search "s-1-tcl_platform"
    while executing
"array anymore $arrayName $sid"
    (procedure "array_foreach" line 12)
    invoked from within
"array_foreach {x y} tcl_platform {set tcl_platform(foo) bar;puts $x->$y}"

Вы установили ловушку на array nextelement, но не на array anymore, что фактически и выявляет проблему(и бросает)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...