2 Stimmen

Prüfen, ob ein Objekt bereits getestet wurde

Ich habe ein Skript, das prüfen soll, ob ein Wert (z. B. eine Option oder ein Funktionsargument) mit einem Modell übereinstimmt. Ich möchte, dass mein Skript in der Lage ist, rekursive Datenstrukturen zu überprüfen. Die Frage ist also: Gibt es einen effizienteren Weg, als über eine Liste zu iterieren, die Verweise auf bereits geprüfte Listen und Dictionaries enthält. Beispiel-Code:

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

Auf der Suche nach einer Möglichkeit zum Sortieren checkedlst (d.h. Verweise zu vergleichen, aber nicht die von ihnen gefundenen Werte) oder sogar einen Hash zu verwenden.

1voto

Bill Odom Punkte 4043

Wie Sie vermutlich schon herausgefunden haben, erlaubt Vim nicht, dass List- oder Dictionary-Variablen als Wörterbuchschlüssel verwendet werden. Das bedeutet, dass Sie zum Beispiel ein "geprüftes" Wörterbuch nicht wie dieses auffüllen können:

" Unless k is a String, this won't work.
:let checked[k] = 1

Es gibt auch keine einfache Möglichkeit, eine eindeutige Zeichenkette aus einer Liste oder einem Wörterbuch zu erzeugen, so dass auch dies nicht zuverlässig ist:

:let checked[ string(k) ] = 1

Ein besserer Ansatz ist es, die Datenstrukturen selbst zu markieren, anstatt zu versuchen, eine Hashtabelle zu erstellen. Wenn es Ihnen nichts ausmacht, Ihre Datenstrukturen vorübergehend schreibgeschützt zu machen, ist eine Möglichkeit, dies zu tun, die Verwendung von :lockvar :

:let someDict = {}
:let someDict['foo'] = [1, 2, 3]
:lockvar 1 someDict

Das markiert someDict als schreibgeschützt. (Die 1 beschränkt das Sperren auf die oberste Ebene des Dictionarys, so dass verschachtelte Strukturen nicht automatisch gesperrt werden). Der Sperrstatus einer Variablen kann wie folgt überprüft werden:

:echo islocked('someDict')
1

:echo islocked("someDict['foo']")
0

:echo islocked("someDict['foo'][0]")
0

Das Entriegeln ist ebenso einfach:

:unlockvar 1 someDict

Jetzt haben wir also eine Technik, um einzelne Ebenen von verschachtelten Datenstrukturen als "geprüft" zu markieren, eine Möglichkeit, abzufragen, ob eine bestimmte Ebene markiert ist oder nicht, und eine Möglichkeit, alle Markierungen zu entfernen, wenn wir fertig sind. Das Ganze zusammenfügen, AlreadyChecked() kann wie folgt geändert werden:

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

Wenn Sie mit der Kontrolle fertig sind, entfernen Sie einfach alle Schlösser:

for obj in a:checkedlst
    unlockvar 1 obj
endfor

Ich hoffe, das hilft. Es ist ein hackish Missbrauch der Sperrfunktion, aber vielleicht wird es tun, was Sie brauchen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X