我猜你已经发现了,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
作为只读的。(The
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
希望这有帮助。这是对锁定设备的一种黑客式的滥用,但也许它可以满足您的需要。