【问题标题】:Checking whether some object has been already tested检查某个对象是否已经过测试
【发布时间】:2010-06-18 16:36:17
【问题描述】:

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

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 进行排序(即比较引用,但不比较它们找到的值)甚至使用哈希。

【问题讨论】:

    标签: vim recursive-datastructures


    【解决方案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 将锁定限制在字典的顶层,因此嵌套结构不会自动锁定。)可以像这样检查变量的锁定状态:

    :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
    

    希望这会有所帮助。这是对锁定功能的恶意滥用,但也许它会满足您的需求。

    【讨论】:

    • 谢谢,如果我将您的答案与deepcopy 结合起来(这将清除锁并使数据独立于其来源),那么它应该可以正常工作。
    • 但是你有一个错误:let someDict{'foo'}=... 会创建一个变量someDictfoo,你应该把它改成someDict.foo 或者someDict["foo"],见:h curly-braces-names。
    • 啊,不错。这是由于在 Perl 和 Vimscript 之间切换太快而导致的。 :-) 我已更正示例以使用正确的语法。很高兴答案仍然有用。
    猜你喜欢
    • 1970-01-01
    • 2011-09-11
    • 1970-01-01
    • 1970-01-01
    • 2021-12-24
    • 1970-01-01
    • 1970-01-01
    • 2017-08-10
    • 2012-09-26
    相关资源
    最近更新 更多