下面是一個例子,其中調用identity
更改返回的值,這似乎表明文檔字符串「返回其參數」。並非完全正確:預計身份是否會返回與其論點不同的東西?
(let [x Double/NaN] (identical? x x)) ;=> false
(let [x (identity Double/NaN)] (identical? x x)) ;=> true
這是預期嗎?或者它與某種程度上的identity
功能有關嗎?
下面是一個例子,其中調用identity
更改返回的值,這似乎表明文檔字符串「返回其參數」。並非完全正確:預計身份是否會返回與其論點不同的東西?
(let [x Double/NaN] (identical? x x)) ;=> false
(let [x (identity Double/NaN)] (identical? x x)) ;=> true
這是預期嗎?或者它與某種程度上的identity
功能有關嗎?
您似乎發現了一個涉及identity
,identical?
以及原語與對象相等的邊界情況。需要注意的是在Java中,java.lang.Double/NaN is a primitive:
public static final double NaN
但相同的比較Java對象:
; clojure.core
(defn identical?
"Tests if 2 arguments are the same object"
{:inline (fn [x y] `(. clojure.lang.Util identical ~x ~y))
:inline-arities #{2}
:added "1.0"}
([x y] (clojure.lang.Util/identical x y)))
// clojure/lang/Util.java
static public boolean identical(Object k1, Object k2){
return k1 == k2;
}
試試這一招NaN的強制轉化成一個Double對象,而不是拆箱原始:
tupelo.core=> (let [x (Double. Double/NaN)]
(spyxx x)
(identical? x x))
x => java.lang.Double->NaN
true
我懷疑原始NaN的自動裝箱可能會/不會出現在不同的使用情況下,這是您所看到的差異的原因。
最後的訣竅與這個問題提出的問題是一樣的:你把NaN放在Double中,就像問題中的身份一樣。這不是一回事。我認爲這個答案缺失的唯一原因是「身份」和「相同?」爲什麼需要自動裝箱。 – amalloy
要一點點顏色添加到艾倫的回答拳擊:
你可能想看看進入==
功能,這是這種方式實現:
public boolean equiv(Number x, Number y){
return x.doubleValue() == y.doubleValue();
}
執行對兩個實際原始的比較double
s。你的例子,與==
:
(let [x (identity Double/NaN)] (== x x))
=> false
(let [x (identity Double/POSITIVE_INFINITY)] (== x x))
=> true
這是怎麼回事?爲什麼NaN == NaN
是假的?那麼,使用==
的原始比較實際上應該返回假爲NaN
。在IEEE 754中奇怪地指定了這種方式,Java的行爲就是這樣。這是唯一的「數字」,與其本身相比,並不等同。
順便說一句,看物體平等如何能夠在Java中一個奇怪的東西,看到這一點:
(identical? 127 127)
=> true
(identical? 128 128)
=> false
這是因爲Java緩存第2^8個無符號整數,所以被比較的127
小號在第一個例子中是相同的對象,但第二個例子中的128
是不同的對象。所以,在檢查平等時需要注意一些問題!
但這裏的主要外賣是:identity
正在工作,因爲它應該!在比較事物時要小心,因爲「平等」的概念並不那麼簡單!
這並沒有回答這個問題,這個問題是關於返回值彼此不同的事實,而不是關於返回值具體是什麼。 –
是否identity
「返回其參數」?
這取決於你的意思論據。
由於Clojure調用函數的方式而出現異常。
IFn
interface的對象。invoke
方法都有Object
參數。所有這一切的結果是,每一個Clojure的函數調用轉換它的每一個參數轉換爲某種Object
- 除了在原語,它被包裹在相應的Java類的身份操作:long
爲Long
,等等。
因此,即使是identity
函數,本質上(defn identity [x] x)
,都不會返回原始參數。它不能,因爲它從來沒有看到它。
例如,讓我們考慮的表達
(inc 3)
數量3
肯定是一個long
。什麼類型是(inc 3)
?讓我們問的Clojure:
(type (inc 3))
=> java.lang.Long
...一個盒裝Long
對象。
坑,都是我們確信3
是一種原始的long
:
(type 3)
=> java.lang.Long
Aaaaaaagh!它也是盒裝!
不一定!你不能說,因爲到type
的身體看到3
的時候,它是盒裝,無論是否它是這樣的讀者/編譯器。 Clojure documentation在這一點上保持沉默。它只是說數字文字通常是按照Java表示的。
所以 - 一般 - 它是評估機制,而不是一個特定的功能(如identity
),它負責裝箱原始參數。這是自動裝箱。
你的例子顯示的是原語持有這樣,未裝箱,至少在let
形式:
(let [x 1.0] (identical? x x)) ;=> false
(let [x (identity 1.0)] (identical? x x)) ;=> true
事實上,identical?
能的1.0
兩個boxings區分表明,保持爲原始double
。 (我使用了一個普通的double
,只是爲了表明這種行爲與特殊值Double/NaN
無關)。
現在讓我們嘗試投入變種數量:
(def x 1.0)
(identical? x x) ;=> true
(let [x (identity x)] (identical? x x)) ;=> true
它的盒裝。
雖然我們在這裏,自動裝箱是冪:
(identical? x (identity x)) ;=> true
上面增加了小到什麼Alan Thompson's和Josh's答案和艾倫馬洛伊的和李的意見包括。我只是覺得他們已經迷上了魚,沒有真正落地。
這可能是由於拳擊 - 「Double/NaN」返回一個原始的'double',在第一個例子中它被裝箱兩次,但在第二個例子中只有一次。 – Lee