Вы можете определять новые методы поиска ключей с помощью
define-hash-table-test. Чтобы использовать эту функцию, вам
необходимо понять, как работают хеш-таблицы, и что означает хеш-код.
Концептуально хеш-таблицу можно представить как большой массив из множества
слотов, каждый из которых может содержать одну ассоциацию. Чтобы найти ключ,
gethash сначала вычисляет целое число, хеш-код, из ключа.
Он может уменьшить это целое число по модулю длины массива, чтобы получить
индекс в массиве. Затем он ищет в этом слоте, а при необходимости и в других
близких слотах, чтобы проверить, нашел ли он искомый ключ.
Таким образом, чтобы определить новый метод поиска ключей, вам необходимо указать как функцию для вычисления хеш-кода из ключа, так и функцию для прямого сравнения двух ключей. Эти две функции должны быть согласованы: то есть, хеш-коды двух ключей должны быть одинаковыми, если ключи сравниваются как равные. Кроме того, поскольку обе функции могут быть вызваны в любое время (например, сборщиком мусора), они должны быть свободны от побочных эффектов, должны быстро выполняться, и их поведение должно зависеть только от свойств ключей, которые не меняются.
Эта функция определяет новый тест для хеш-таблицы с именем name.
После определения name таким образом вы можете использовать его
в качестве аргумента test в make-hash-table.
Когда вы это делаете, хеш-таблица будет использовать test-fn
для сравнения значений ключей и hash-fn для вычисления
хеш-кода из значения ключа.
Функция test-fn должна принимать два аргумента, два ключа, и
возвращать не-nil, если они считаются одинаковыми.
Функция hash-fn должна принимать один аргумент, ключ, и возвращать целое число, которое является хеш-кодом этого ключа. Для хороших результатов функция должна использовать весь диапазон фиксированных чисел для хеш-кодов, включая отрицательные фиксированные числа.
Указанные функции сохраняются в списке свойств name под
свойством hash-table-test; форма значения свойства —
(test-fn hash-fn).
Эта функция возвращает хеш-код для объекта Lisp obj. Это целое число, отражающее содержимое obj и другие объекты Lisp, на которые он указывает.
Если два объекта obj1 и obj2 равны
equal, то (sxhash-equal obj1)
и (sxhash-equal obj2) будут одинаковыми
целыми числами.
Если два объекта не равны equal, значения, возвращаемые
sxhash-equal, обычно разные, но не всегда. sxhash-equal
разработан так, чтобы быть достаточно быстрым (поскольку он используется для
индексирования хеш-таблиц), поэтому он не будет глубоко рекурсировать во вложенные
структуры. Кроме того, иногда, по счастливой случайности, вы можете встретить
два внешне разных простых объекта, которые дают одинаковый результат от
sxhash-equal. Поэтому, в общем случае, вы не можете использовать
sxhash-equal для проверки того, изменился ли объект.
Примечание для Common Lisp: В Common Lisp аналогичная функция
называется sxhash. Emacs предоставляет это имя как совместимый
псевдоним для sxhash-equal.
Эта функция возвращает хеш-код для объекта Lisp obj. Ее результат отражает идентичность obj, но не его содержимое.
Если два объекта obj1 и obj2 равны
eq, то (sxhash-eq obj1)
и (sxhash-eq obj2) будут одинаковыми
целыми числами.
Эта функция возвращает хеш-код для объекта Lisp obj,
подходящий для сравнения eql. Другими словами, он отражает
идентичность obj, за исключением случая, когда объект является
большим числом или числом с плавающей запятой, в котором генерируется
хеш-код для значения.
Если два объекта obj1 и obj2 равны
eql, то (sxhash-eql obj1)
и (sxhash-eql obj2) будут одинаковыми
целыми числами.
Этот пример создает хеш-таблицу, ключами которой являются строки, сравниваемые без учета регистра.
(defun string-hash-ignore-case (a) (sxhash-equal (upcase a))) (define-hash-table-test 'ignore-case 'string-equal-ignore-case 'string-hash-ignore-case) (make-hash-table :test 'ignore-case)
Вот как вы могли бы определить тест хеш-таблицы, эквивалентный
заранее определенному значению теста equal. Ключами могут
быть любые объекты Lisp, и объекты, которые выглядят одинаково, считаются одним
ключом.
(define-hash-table-test 'contents-hash 'equal 'sxhash-equal) (make-hash-table :test 'contents-hash)
Программы на Lisp не должны полагаться на сохранение хеш-кодов между сессиями Emacs, поскольку реализация хеш-функций использует некоторые детали хранения объектов, которые могут меняться между сессиями и между различными архитектурами.