2.8 Предикаты равенства

Здесь описаны функции, проверяющие равенство двух объектов. Другие функции проверяют равенство содержимого объектов конкретных типов, например строк. Для этих предикатов обратитесь к соответствующей главе, описывающей тип данных.

Функция: eq object1 object2

Эта функция возвращает t, если object1 и object2 являются одним и тем же объектом, и nil в противном случае.

Если object1 и object2 — символы с одинаковыми именами, обычно они являются одним и тем же объектом — но см. Создание и интернирование символов для исключений. Для других нечисловых типов (например, списков, векторов, строк) два аргумента с одинаковым содержимым или элементами не обязательно являются eq друг другу: они eq только если являются одним и тем же объектом, то есть изменение содержимого одного отразится таким же изменением содержимого другого.

Если object1 и object2 — числа различных типов или значений, они не могут быть одним объектом, и eq возвращает nil. Если они — фикснумы с одинаковым значением, то они являются одним объектом, и eq возвращает t. Если они были вычислены по отдельности, но случайно имеют одинаковое значение и одинаковый не-фикснумный числовой тип, то они могут быть одним объектом или нет, и eq возвращает t или nil в зависимости от того, создал ли интерпретатор Lisp один объект или два.

Если object1 или object2 — символ с позицией, eq рассматривает его как голый символ, когда symbols-with-pos-enabled не равно nil (см. Символы с позицией).

(eq 'foo 'foo)
     ⇒ t

(eq ?A ?A)
     ⇒ t

(eq 3.0 3.0)
     ⇒ t или nil
;; Равные числа с плавающей точкой могут быть или не быть одним объектом.

(eq (make-string 3 ?A) (make-string 3 ?A))
     ⇒ nil

(eq "asdf" "asdf")
     ⇒ t или nil
;; Равные строковые константы могут быть или не быть одним объектом.

(eq '(1 (2 (3))) '(1 (2 (3))))
     ⇒ nil

(setq foo '(1 (2 (3))))
     ⇒ (1 (2 (3)))
(eq foo foo)
     ⇒ t
(eq foo '(1 (2 (3))))
     ⇒ nil

(eq [(1 2) 3] [(1 2) 3])
     ⇒ nil

(eq (point-marker) (point-marker))
     ⇒ nil

Функция make-symbol возвращает неинтернированный символ, отличный от символа, который используется при записи имени в выражении Lisp. Различные символы с одинаковым именем не являются eq. См. Создание и интернирование символов.

(eq (make-symbol "foo") 'foo)
     ⇒ nil

Байт-компилятор Emacs Lisp может сворачивать идентичные литеральные объекты, например литеральные строки, в ссылки на один и тот же объект, в результате чего скомпилированный в байт-код код будет сравнивать такие объекты как eq, в то время как интерпретируемая версия того же кода — нет. Поэтому ваш код никогда не должен полагаться на то, что объекты с одинаковым литеральным содержимым являются eq или не являются eq; вместо этого следует использовать функции, сравнивающие содержимое объектов, такие как equal, описанная ниже. Аналогично, ваш код не должен изменять литеральные объекты (например, добавлять текстовые свойства к литеральным строкам), поскольку это может повлиять на другие литеральные объекты с тем же содержимым, если байт-компилятор сворачивает их.

Функция: equal object1 object2

Эта функция возвращает t, если object1 и object2 имеют равные компоненты, и nil в противном случае. В то время как eq проверяет, являются ли аргументы одним объектом, equal заглядывает внутрь неидентичных аргументов, чтобы увидеть, совпадают ли их элементы или содержимое. Таким образом, если два объекта являются eq, то они equal, но обратное не всегда верно.

(equal 'foo 'foo)
     ⇒ t

(equal 456 456)
     ⇒ t

(equal "asdf" "asdf")
     ⇒ t
(eq "asdf" "asdf")
     ⇒ nil

(equal '(1 (2 (3))) '(1 (2 (3))))
     ⇒ t
(eq '(1 (2 (3))) '(1 (2 (3))))
     ⇒ nil

(equal [(1 2) 3] [(1 2) 3])
     ⇒ t
(eq [(1 2) 3] [(1 2) 3])
     ⇒ nil

(equal (point-marker) (point-marker))
     ⇒ t

(eq (point-marker) (point-marker))
     ⇒ nil

Функция equal сравнивает строки и bool-векторы по значению. Числа сравниваются по типу и числовому значению с использованием eql. Списки, cons-ячейки, векторы, записи, маркеры, символьные таблицы, объекты шрифтов и функциональные объекты (замыкания)2 сравниваются рекурсивно с помощью equal для их составных частей.

Сравнение строк чувствительно к регистру, но не учитывает текстовые свойства — оно сравнивает только символы в строках. См. Текстовые свойства. Используйте equal-including-properties для сравнения также текстовых свойств. По техническим причинам однобайтовая строка и многобайтовая строка являются equal тогда и только тогда, когда они содержат одну и ту же последовательность кодов символов и все эти коды находятся в диапазоне от 0 до 127 (ASCII).

(equal "asdf" "ASDF")
     ⇒ nil

Если object1 или object2 содержит символы с позицией, equal обрабатывает их так, как если бы они были голыми символами, когда symbols-with-pos-enabled не равно nil. В противном случае equal сравнивает два символа с позицией, сравнивая их компоненты. См. Символы с позицией.

Другие объекты считаются equal только если они eq. Например, два различных буфера никогда не считаются equal, даже если их текстовое содержимое одинаково.

Для equal равенство определено рекурсивно; например, для двух cons-ячеек x и y (equal x y) возвращает t тогда и только тогда, когда оба выражения ниже возвращают t:

(equal (car x) (car y))
(equal (cdr x) (cdr y))

Сравнение циклических списков может вызвать глубокую рекурсию, приводящую к ошибке, и это может привести к неинтуитивному поведению, например, когда (equal a b) возвращает t, а (equal b a) вызывает ошибку.

Функция: equal-including-properties object1 object2

Эта функция ведёт себя как equal во всех случаях, но дополнительно требует, чтобы для равенства двух строк они имели одинаковые текстовые свойства.

(equal "asdf" (propertize "asdf" 'asdf t))
     ⇒ t
(equal-including-properties "asdf"
                            (propertize "asdf" 'asdf t))
     ⇒ nil

Сноски

(2)

Однако равенство различных функциональных объектов в общем случае не гарантируется.