创建哈希表的主要函数是 make-hash-table。
该函数根据指定的参数创建一个新的哈希表。参数应由关键字(专门识别的特定符号)与对应的值交替组成。
make-hash-table 支持多个关键字,但你真正需要了解的只有两个::test 和 :weakness。
:test test指定该哈希表的键查找比较方式。默认值为 eql,其他可选值为 eq 和 equal:
eql如果键是数字,当它们满足 equal 时视为相同,即数值相等,且同为整数或同为浮点数;否则,两个不同的对象永远不相同。
eq任意两个不同的 Lisp 对象,作为键时都视为不同。
equal如果两个 Lisp 对象按照 equal 函数判定为相等,则它们作为键时视为相同。
你可以使用 define-hash-table-test(see 定义哈希表比较方式)为 test 定义更多可选的比较方式。
:weakness weak哈希表的 “弱引用(weakness)” 属性用于指定:哈希表中键(key)或值(value)的存在,是否会阻止它们被垃圾回收(garbage collection)。
参数 weak 的取值必须是 nil、key、value、key-or-value、key-and-value 之一,其中 t 是 key-and-value 的别名。若 weak 设为 key,则哈希表不会阻止其键被垃圾回收(前提是这些键在其他地方无引用);当某个键被回收时,对应的键值对会从哈希表中移除。
若 weak 设为 value,则哈希表不会阻止其值被垃圾回收(前提是这些值在其他地方无引用);当某个值被回收时,对应的键值对会从哈希表中移除。
若 weak 设为 key-and-value 或 t,则只有当键和值都处于 “存活” 状态时,对应的键值对才会被保留。因此,哈希表既不会保护键、也不会保护值免于垃圾回收;只要键或值任意一方被回收,该键值对就会被移除。
如果 weak 为 key-or-value,那么键或值其中任意一个存活,就能保留该键值对。因此,只有当键和值都将被垃圾回收时(若非因为弱哈希表的引用),对应的键值对才会从哈希表中移除。
weak 的默认值为 nil,此时哈希表中的所有键和值都会被保护,不会被垃圾回收。
:size size该参数用于提示你计划在哈希表中存放多少个键值对。如果你知道大致数量,通过该参数指定可以略微提升效率;但由于哈希表内存是自动管理的,这种速度提升通常并不显著。
你还可以使用哈希表的打印表示形式来创建哈希表。只要指定哈希表中的每个元素都有合法的读取语法(see 打印表示与读入语法),Lisp 读取器就能解析这种打印表示。
例如,下面的表达式定义了一个哈希表,其中包含键 key1 和 key2(均为符号),分别对应值 val1(符号)和 300(数字)。
#s(hash-table data (key1 val1 key2 300))
需要注意的是,在 Emacs Lisp 代码中使用这种方式时,是否会创建新的哈希表是未定义行为。如果你希望创建新的哈希表,应当始终使用 make-hash-table 函数(see 自求值形式)。
哈希表的打印表示形式以 ‘#s’ 开头,其后紧跟一个以 ‘hash-table’ 为首元素的列表。列表的其余部分由零个或多个 “属性 - 值” 对组成,用于指定哈希表的属性和初始内容。这些属性与值会按字面量读取。合法的属性名包括 test、weakness 和 data:其中 data 属性应是一个包含键值对的列表,用于设定哈希表的初始内容;其余属性的含义与上文所述 make-hash-table 函数的对应关键字(:test 和 :weakness)完全一致。
注意:你不能直接指定初始内容中包含无读取语法的对象(例如缓冲区、窗口框架)的哈希表。这类对象可以在哈希表创建之后再添加进去。