检查某个对象是否已经过测试

时间:2010-06-18 16:36:18

标签: vim recursive-datastructures

我有一个脚本,用于检查某个值(例如选项或函数参数)是否与某个模型匹配。我希望我的脚本能够检查递归数据结构。所以问题是:是否有更有效的方法,然后迭代包含对已检查的列表和词典的引用的某个列表。示例代码:

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 个答案:

答案 0 :(得分:1)

正如我猜你已经发现的那样,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将锁定限制在Dictionary的顶层,因此嵌套结构不会自动锁定。)可以像这样检查变量的锁定状态:

: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

希望这会有所帮助。这是对锁定设施的滥用,但也许它会做你需要的。