EQ 和 EQL 之间的区别
-
EQ
检查两个值是否具有相同的内存地址:换句话说,它检查这两个值是否实际上是相同的,相同的对象。因此,它可以被认为是身份测试,并且应该仅应用于结构:conses,数组,结构,对象,通常用于查看你是否正在处理通过不同路径到达的相同对象,或者通过别名来处理不同的变量。 -
EQL
检查两个结构是否是同一个对象(如EQ
),或者它们是否是相同的非结构化值(即相同类型的数字或字符值的相同数值)。由于它包含EQ
运算符并且也可以用于非结构化值,因此是最重要和最常用的运算符,几乎所有需要相等比较的原始函数(如MEMBER
) 默认使用此运算符。
因此,(EQ X Y)
总是意味着 (EQL X Y)
,而反之亦然。
一些例子可以清除两个运算符之间的差异:
(eq 'a 'a)
T ;; => since two s-expressions (QUOTE A) are `internalized` as the same symbol by the reader.
(eq (list 'a) (list 'a))
NIL ;; => here two lists are generated as different objects in memory
(let* ((l1 (list 'a))
(l2 l1))
(eq l1 l2))
T ;; => here there is only one list which is accessed through two different variables
(eq 1 1)
?? ;; it depends on the implementation: it could be either T or NIL if integers are `boxed`
(eq #\a #\a)
?? ;; it depends on the implementation, like for numbers
(eq 2d0 2d0)
?? ;; => dependes on the implementation, but usually is NIL, since numbers in double
;; precision are treated as structures in many implementations
(let ((a1 2d0)
(a2 2d0))
(eq a1 a2))
?? ;; => also in this case the results depends on the implementation
让我们用 EQL
尝试相同的例子:
(eql 'a 'a)
T ;; => equal because they are the same value, as for EQ
(eql (list 'a) (list 'a))
NIL ;; => different because they different objects in memory, as for EQ
(let* ((l1 (list 'a))
(l2 l1))
(eql l1 l2))
T ;; => as above
(eql 1 1)
T ;; they are the same number, even if integers are `boxed`
(eql #\a #\a)
T ;; they are the same character
(eql 2d0 2d0)
T ;; => they are the same number, even if numbers in double precision are treated as
;; structures in many implementations
(let ((a1 2d0)
(a2 2d0))
(eql a1 a2))
T ;; => as before
(eql 2 2.0)
NIL;; => since the two values are of a different numeric type
从示例中我们可以看出为什么 EQL
运算符应该用于可移植地检查所有值的相同性,结构化和非结构化,以及为什么实际上许多专家建议不要使用 EQ
。