Warum gibt gethash den Wert meines Schlüssels nicht zurück?

8

Erfahrener Lisp-, Schema- und Clojure-Programmierer, der von Python zu Elisp wechselt, um routinemäßige, alltägliche Grundaufgaben zu automatisieren: Ich habe eine enorme Überraschung von den folgenden in bekommen ielm

ELISP> (setq h2 (make-hash-table))
#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ())
ELISP> (puthash "a" 1 h2)
1 (#o1, #x1, ?\C-a)
ELISP> (gethash "a" h2)
nil

huh? Der Schlüssel und der Wert scheinen vorhanden zu sein:

ELISP> h2
#s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ("a" 1))

Ich klatsche auf die Stirn. Mir muss etwas völlig Offensichtliches fehlen. Info sagt:

-- Function: gethash key table &optional default
 This function looks up KEY in TABLE, and returns its associated
 VALUE—or DEFAULT, if KEY has no association in TABLE.

groß. Mal sehen, ob wir gethashetwas anderes zurückgeben können als nil:

ELISP> (gethash "a" h2 'fubar) 
fubar

Beeindruckend. Ok, ich bin viel dümmer als ich dachte. Was um alles in der Welt mache ich falsch?

Reb.Cabin
quelle

Antworten:

13

Der Standard-Mitgliedschaftstest für eine Hash-Tabelle lautet eql. Wenn Sie eine Zeichenfolge als Schlüssel verwenden möchten, setzen Sie sie equalstattdessen auf:

(setf hash (make-hash-table :test #'equal))
(puthash "a" 1 hash)
(gethash "a" hash)                      ; ==> 1

Als Referenz ist hier der relevante Teil der Dokumentzeichenfolge:

make-hash-table ist eine integrierte Funktion in "C-Quellcode".

(make-hash-table &rest KEYWORD-ARGS)

Erstellen Sie eine neue Hash-Tabelle und geben Sie sie zurück.

Argumente werden als Schlüsselwort / Argument-Paare angegeben. Folgende Argumente sind definiert:

:testTEST - TEST muss ein Symbol sein, das angibt, wie Schlüssel verglichen werden. Standard ist eql. Vordefinierte sind die Tests eq, eqlund equal. Vom Benutzer bereitgestellte Test- und Hash-Funktionen können über angegeben werden define-hash-table-test.

Dan
quelle
Ich denke, technisch gesehen übergeben Sie :testin Ihrem Beispiel kein Symbol als Parameter ...
Sean
string-equalkönnte einige Vorteile gegenüber haben, equalwenn ich weiß, dass meine Hash-Tabelle nur Zeichenfolgen als Schlüssel enthält. Ich bin mir nicht sicher, warum elisp beides hat string-equalund equalweil equales an jedem Ort string-equalverwendet werden kann, der modulo verwendet werden kann, die Tatsache, dass string-equalTypfehler ausgelöst werden, wenn Sie ihm keine Zeichenfolgen geben. Vielleicht ist das ein gewünschtes Verhalten.
Reb.Cabin