这是一个调用identity
更改返回值的示例,在我看来,这表明文档字符串"返回其参数。"并非完全正确:
(let [x Double/NaN] (identical? x x)) ;=> false
(let [x (identity Double/NaN)] (identical? x x)) ;=> true
这是预期的吗?或者它是identity
函数的错误?
答案 0 :(得分:8)
您似乎找到了涉及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的自动装箱可能会/可能不会在不同的用例中出现,这是您所看到的差异的原因。
答案 1 :(得分:3)
为艾伦关于拳击的答案添加一点颜色:
您可能需要查看==
函数,该函数以这种方式实现:
public boolean equiv(Number x, Number y){
return x.doubleValue() == y.doubleValue();
}
这将执行两个实际double
的原始比较。您的示例,==
:
(let [x (identity Double/NaN)] (== x x))
=> false
(let [x (identity Double/POSITIVE_INFINITY)] (== x x))
=> true
发生了什么?为什么NaN == NaN
是假的?好吧,使用==
的原始比较实际上应该为NaN
返回false。它在IEEE 754中以这种方式奇怪地指定并且Java以这种方式运行。它是唯一的"数字"与自身相比,它不等于自己。
顺便说一句,要了解对象相等在Java中是多么奇怪,请参阅:
(identical? 127 127)
=> true
(identical? 128 128)
=> false
这是因为java缓存了前2 ^ 8个无符号整数,因此被比较的127
在第一个示例中是相同的对象,但第二个示例中的128
是不同的对象。因此,检查平等时需要注意一些问题!
但这里的主要内容是:identity
正常运作!在比较事物时要小心,因为"平等"不是那么简单!
答案 2 :(得分:0)
identity
“返回其参数”吗?
这取决于参数的含义。
由于Clojure调用函数的方式而产生异常。
IFn
interface的对象。invoke
之一
方法 - 为arity重载 - 函数对象。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
这两个标记的事实表明它被保存为原始double
。 (我使用了普通的double
,只是为了表明行为与特殊值Double/NaN
无关。
现在让我们尝试将数字放在var:
中(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答案以及Alan Malloy和Lee的评论所构成的内容几乎没有什么影响。我只觉得他们已经迷上了鱼并且没有实际登陆它。