正如我猜你已經發現,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