3.10 散列表

散列表实现了键值映射,其中键和值都可以是任意 Racket 值, 访问和更新该表的操作通常是常量时间的。根据散列表以 make-hashmake-hasheqv 还是 make-hasheq 来创建,其键分别用 equal?eqv?eq? 来比较。

例如:
> (define ht (make-hash))
> (hash-set! ht "apple" '(red round))
> (hash-set! ht "banana" '(yellow long))
> (hash-ref ht "apple")

'(red round)

> (hash-ref ht "coconut")

hash-ref: no value found for key

  key: "coconut"

> (hash-ref ht "coconut" "not there")

"not there"

函数 hashhasheqvhasheq 均会根据初始的键值集合来创建不可变的散列表。其中每个值都作为其键之后的参数提供。 不可变的散列表可通过 hash-set 来扩展, 它会以常量时间产生一个新的不可变散列表。

例如:
> (define ht (hash "apple" 'red "banana" 'yellow))
> (hash-ref ht "apple")

'red

> (define ht2 (hash-set ht "coconut" 'brown))
> (hash-ref ht "coconut")

hash-ref: no value found for key

  key: "coconut"

> (hash-ref ht2 "coconut")

'brown

不可变散列表的字面量可使用 #hash(对应基于 equal? 的表)、 #hasheqv(对应基于 eqv? 的表)或 #hasheq(对应基于 eq? 的表)写成表达式的形式。括号括住的序列必须紧跟 #hash#hasheq#hasheqv 其中每个元素都是以点号分隔的键-值对。 #hash 等形式隐式地用 quote 引述了其键值的子形式。

例如:
> (define ht #hash(("apple" . red)
                   ("banana" . yellow)))
> (hash-ref ht "apple")

'red

+The Racket ReferenceReading Hash Tables一节中阐述了散列表字面语法的要点。

可变和不可变散列表的打印结果都与不可变散列表相同。如果所有的键和值均可使用 quote 来表达,那么就使用引述的 #hash#hasheqv#hasheq 形式,否则使用 hashhasheqhasheqv 来表示:

例如:
> #hash(("apple" . red)
        ("banana" . yellow))

'#hash(("banana" . yellow) ("apple" . red))

> (hash 1 (srcloc "file.rkt" 1 0 1 (+ 4 4)))

(hash 1 (srcloc "file.rkt" 1 0 1 8))

可变散列表能够可选地将其键保留为弱引用的,这样只要键在其它地方被保留, 该映射就会被保留。

例如:
> (define ht (make-weak-hasheq))
> (hash-set! ht (gensym) "can you see me?")
> (collect-garbage)
> (hash-count ht)

0

请注意,在弱引用散列表中,只要值对应的键可访问,那么该值也是强引用的。 当值又引用回其键时,会创建一个 catch-22 依赖,这样该映射就会永久保留。 要打破这种循环,需将键映射到一个 ephemeron(短命对象)来将值与其键配对 (散列表中二者的隐式配对除外)。

+The Racket ReferenceEphemerons一节中阐述了使用 ephemeron的要点。

例如:
> (define ht (make-weak-hasheq))
> (let ([g (gensym)])
    (hash-set! ht g (list g)))
> (collect-garbage)
> (hash-count ht)

1

> (define ht (make-weak-hasheq))
> (let ([g (gensym)])
    (hash-set! ht g (make-ephemeron g (list g))))
> (collect-garbage)
> (hash-count ht)

0

+The Racket ReferenceHash Tables一节中提供了关于hash tables and hash-table procedures的更多信息。

+The Racket ReferenceHash Tables一节中提供了关于散列表及其过程的更多信息。