mengapa gethash tidak mengembalikan nilai kunci saya?

8

Cisp, skema, clojure programmer berpengalaman membuat pindah ke elisp dari python untuk mengotomatisasi rutin, setiap hari, tugas-tugas dasar: Saya mendapat kejutan besar dari yang berikut di 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

Hah? Kunci dan nilai tampaknya ada:

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

/ Menampar dahi. Saya pasti kehilangan sesuatu yang sangat jelas. Info mengatakan:

-- 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.

Bagus. Mari kita lihat apakah kita bisa gethashmengembalikan apa pun selain nil:

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

Wow. Ok, saya jauh lebih bodoh dari yang saya kira. Apa yang saya lakukan salah?

Reb.Cabin
sumber

Jawaban:

13

Tes keanggotaan default untuk tabel hash adalah eql. Jika Anda ingin menggunakan string sebagai kunci, setel ke equal:

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

Untuk referensi, inilah bagian yang relevan dari docstring:

make-hash-table adalah fungsi bawaan dalam `kode sumber C '.

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

Buat dan kembalikan tabel hash baru.

Argumen ditentukan sebagai pasangan kata kunci / argumen. Argumen berikut didefinisikan:

:testTEST - TEST harus berupa simbol yang menentukan cara membandingkan kunci. Defaultnya adalah eql. Yang telah ditetapkan adalah tes eq, eqldan equal. Fungsi tes dan hash yang disediakan pengguna dapat ditentukan melalui define-hash-table-test.

Dan
sumber
Saya kira secara teknis Anda tidak melewati simbol sebagai :testparameter dalam contoh Anda ...
Sean
string-equalmungkin memiliki beberapa kelebihan dibandingkan equaljika saya tahu hash-table saya hanya memiliki string sebagai kunci. Saya tidak yakin mengapa elisp memiliki keduanya string-equaldan equal, karena equaldapat digunakan di mana saja yang string-equaldapat digunakan modulo fakta yang string-equalmelempar kesalahan ketik ketika Anda tidak memberikan string. Mungkin itu perilaku yang diinginkan.
Reb.Cabin