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
。