检查是否一些对象已经被测试
问题描述:
我有一个用来检查某个值(例如,选项或功能参数)是否一些模型相匹配的脚本。我希望我的脚本能够检查递归数据结构。所以,问题是:有没有更有效的方法然后再遍历包含引用到已经选中的列表和字典的一些列表。示例代码:检查是否一些对象已经被测试
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不会允许列表或解释变量作为字典键。这意味着你不能,例如,可以填充一个“检查”字典是这样的:
" 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'(与其来源无关,将清除锁,使数据)你的答案,那么它应该工作的罚款。 – ZyX 2010-08-08 16:13:10
但你有一个错误:'让someDict {“富”} = ...'将创建一个变量'someDictfoo',你应该把它要么改变为'someDict.foo'或'someDict [“富”]',参见':h curly-braces-names'。 – ZyX 2010-08-08 16:17:19
啊,很好。这是Perl和Vimscript之间切换太快的原因。 :-)我已经更正了这些示例以使用正确的语法。很高兴答案仍然有用。 – 2010-08-09 17:20:48