Проверка, был ли какой-либо объект уже протестирован - PullRequest
2 голосов
/ 18 июня 2010

У меня есть скрипт, предназначенный для проверки того, соответствует ли какое-либо значение (например, параметр или аргумент функции) какой-либо модели. Я хочу, чтобы мой скрипт мог проверять рекурсивные структуры данных. Таким образом, вопрос заключается в следующем: существует ли более эффективный способ, чем перебирать какой-либо список, содержащий ссылки на уже проверенные списки и словари. Пример кода:

function s:AlreadyChecked(arg, checkedlst)
    if type(a:arg)!=type([]) && type(a:arg)!=type({})
        return 0
    endif
    for obj in a:checkedlst
        if a:arg is obj
            return 1
        endif
    endfor
    call add(a:checkedlst, a:arg)
    return 0
endfunction

В поисках способа сортировки checkedlst (то есть сравнения ссылок, но не найденных ими значений) или даже использования хэша.

1 Ответ

1 голос
/ 18 июля 2010

Как я полагаю, вы уже обнаружили, Vim не позволяет использовать переменные List или Dictionary в качестве словарных ключей.Это означает, что вы не можете, например, заполнить «проверенный» словарь следующим образом:

" Unless k is a String, this won't work.
:let checked[k] = 1

Также не хватает простого способа генерировать уникальную строку из списка или словаря, так что это не так.либо надежный:

:let checked[ string(k) ] = 1

Лучшим подходом является пометка самих структур данных, а не попытка создать хеш-таблицу.Если вы не против временно сделать ваши структуры данных доступными только для чтения, один из способов сделать это - использовать :lockvar:

:let someDict = {}
:let someDict['foo'] = [1, 2, 3]
:lockvar 1 someDict

, который помечает someDict только для чтения.(1 ограничивает блокировку верхним уровнем словаря, поэтому вложенные структуры не блокируются автоматически.) Состояние блокировки переменной можно проверить следующим образом:

:echo islocked('someDict')
1

:echo islocked("someDict['foo']")
0

:echo islocked("someDict['foo'][0]")
0

Разблокировка также проста:

:unlockvar 1 someDict

Итак, теперь у нас есть метод для обозначения отдельных уровней вложенных структур данных как «проверенных», способ запрашивать, помечен ли определенный уровень или нет, и способ удалить все отметкикогда мы закончимСобрав все это вместе, AlreadyChecked() можно изменить следующим образом:

function! s:AlreadyChecked(arg, checkedlst)

    if type(a:arg)!=type([]) && type(a:arg)!=type({})
        return 0
    endif

    " If this particular List or Dictionary has already been checked, just
    " return true immediately.
    "
    if islocked('a:arg')
        echo "Already checked."
        return 1
    endif

    " Lock the List or Dictionary to mark this item as already
    " checked. Note that only the top level of the List or Dictionary
    " is locked; values are not locked.
    "
    lockvar 1 a:arg

    " Remember everything we've locked, so it can be unlocked once
    " we're done.
    "
    call add(a:checkedlst, a:arg)

    return 0

endfunction

Как только вы закончите проверку, просто удалите все блокировки:

for obj in a:checkedlst
    unlockvar 1 obj
endfor

Надеюсь, это поможет.Это хакерское злоупотребление блокировкой, но, возможно, оно сделает то, что вам нужно.

...