# 2.8 相等谓语

这里我们描述测试两个对象之间相等性的函数。其他函数测试特定类型对象（例如字符串）之间内容的相等性。对于这些谓词，请参阅描述数据类型的相应章节。

Function: **eq** *object1 object2*

如果object1和object2是同一个对象，则此函数返回`t`，否则返回`nil`。

如果object1和object2是同名的符号，它们通常是同一个对象——但请参阅[创建符号](https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html)以了解例外情况。对于其他非数字类型（例如，列表、向量、字符串），具有相同内容或元素的两个参数不一定相互`eq`：当且仅当它们是同一个对象时，它们才`eq`，这意味着其中一个对象的内容发生变化时，相同的变化会体现在另一个对象的内容上。

如果object1和object2是具有不同类型或值的数字，则它们不可能是同一个对象，返回`nil`。如果它们是具有相同值的 fixnum，则它们是相同的对象并返回`t`。如果它们是单独计算的，但碰巧具有相同的值和相同的数字类型，那么它们可能是也可能不是同一个对象，返回`t`或`nil` 取决于 Lisp 解释器创建了一个还是两个对象。

```
(eq 'foo 'foo)
     ⇒ t

(eq ?A ?A)
     ⇒ t

(eq 3.0 3.0)
     ⇒ t or nil
;; Equal floats may or may not be the same object.

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

(eq "asdf" "asdf")
     ⇒ t or nil
;; Equal string constants or may not be the same object.

(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`。请参阅[创建符号](https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html)。

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

Emacs Lisp 字节编译器可能会将相同的文字对象（例如文字字符串）折叠为对同一对象的引用，但解释器可能并不会这么做。因此，你的代码永远不要使用 eq 去比较两者的文本意义，你应该使用 equal 函数去比较文本意义。

Function: equal object1 object2

如果object1和object2具有相同的组件，则此函数返回`t`，否则返回`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
```

字符串的比较区分大小写，但不考虑文本属性——它只比较字符串中的字符。请参阅[文本属性](https://www.gnu.org/software/emacs/manual/html_node/elisp/Text-Properties.html)。使用`equal-including-properties`也比较文本属性。出于技术原因，当且仅当单字节字符串和多字节字符串包含相同的字符代码序列，并且所有这些代码都在 0 到 127 ( ASCII )范围内时，它们才`equal`。

```
(equal "asdf" "ASDF")
     ⇒ nil
```

但是，两个不同的缓冲区从不`equal`，即使它们的文本内容相同。

对于`equal`，相等是递归定义的；例如，给定两个节点X和Y， 当且仅当下面两个表达式同时返回`t`时返回`t`。

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

因此，比较循环列表可能会导致导致错误的深度递归，这可能会导致违反直觉的行为，例如 `(equal a b)`返回`t`而`(equal b a)` 发出错误信号。

Function: equal-including-propertied object1 object2

此函数在所有情况下的行为都类似`equal`，但此外，若要求两个字符串相等，那么它们具有的文本属性也必须相同。

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