达特有两个:
==
和identical()
的顶级函数。 通过选择语法,想要比==
更频繁地使用Dart的identical()
运算符感觉很自然,我喜欢这样。事实上,Section on Equality的Idiomatic Dart表示“在实践中,您很少需要使用”identical()
。
在最近对one of my questions concerning custom filters的回答中,似乎 Angular Dart 赞成在尝试确定是否更改模型时使用identical()
而不是==
已达到稳定状态。 (出于效率的原因,我认为,对于大型模型,这是有道理的。)
这让我想到int
的身份,所以我写了identical()
对int
的一些测试。虽然我预计小int
s 可能“实习/缓存”(例如类似于Java's Integer.valueOf()
所做的事情),令我惊讶的是,我可以'似乎生成两个相等但不相同的int
。我得到double
的类似结果。
int
和double
值是否被实习/缓存?或者也许identical()
特别对待他们?来自Java背景,我过去等同于Dart's:
==
到Java的equal()
方法和identical()
到Java的等式测试==
。但现在看来错了。有谁知道发生了什么事?
答案 0 :(得分:4)
数字是专门处理的。如果它们的位模式相同,则它们必须相同(尽管如果这包括不同版本的NaN,仍然存在争议)。
主要原因是期望,泄漏内部细节和效率。
期望:用户希望数字相同。与常识相反,x == y(对于两个整数)但不相同(x,y)。
内部细节泄漏:VM使用SMI(SMall整数)来表示特定范围内的整数(32位计算机上为31位,64位计算机上为63位)。这些是规范化的,并且总是相同的。公开此内部实现细节会导致结果不一致,具体取决于您运行的平台。
效率:VM希望尽可能地取消数字。例如,在方法内部,双精度数经常被移入寄存器。但是,跟踪原始盒子可能很麻烦且很困难。
foo(x, y) {
var result = x;
while(y-- > 0) {
result += x;
}
return result;
}
假设VM优化了此函数并将result
移动到寄存器中(在此过程中取消装箱x
)。这允许紧密循环,然后有效地修改result
。当y
为0时,会发生这种困难的情况。循环不会执行,foo
将直接返回x
。换句话说,以下内容必须如此:
var x = 5.0;
identical(x, foo(x, 0)); // should be true.
如果VM在方法result
中取消装箱foo
变量,则需要为result
分配一个新框,因此identical
调用将返回{{ 1}}。
通过修改false
的定义,可以避免所有这些问题。但是,identical
支票的费用很低。
答案 1 :(得分:3)
好像我发布得太快了。我偶然发现了Dart问题13084: Spec says identical(1.0, 1) is true, even if they have different types,这导致我进入Object Identity language spec的Dart部分。 (我之前在规范中搜索了相等但不是对象标识。)
以下是摘录:
The predefined dart function identical() is defined such that identical(c1, c2) iff:
- c1 evaluates to either null or an instance of
bool and c1 == c2, OR
- c1 and c2 are instances of int and c1 == c2, OR
- c1 and c2 are constant strings and c1 == c2, OR
- c1 and c2 are instances of double and one of the following holds: ...
还有更多处理列表,地图和常量对象的子句。有关详细信息,请参阅language spec。因此,identical()
不仅仅是参考平等的简单测试。
答案 2 :(得分:1)
我不记得这个的来源,但是在dartlang.org或问题跟踪器的某个地方,据说num
,int
和double
确实得到了特殊待遇。其中一种特殊处理方法是,出于性能原因,您不能将这些类型子类化,但可能还有更多。究竟这种特殊处理方法究竟是什么,可能只有开发人员才能回答,或者可能是那些熟悉规范的人,但有一点可以推断:
数字类型是dart对象 - 它们具有可以在其实例上调用的方法。但它们也具有原始数据类型的特性,因为您可以int i = 3;
,而纯对象应该在某处具有new
关键字。这与Java不同,Java中存在真实的原始类型和包装它们的真实对象并暴露实例方法。
虽然技术细节肯定更复杂,但如果你把dart数字看作是对象和原始的混合,你与Java的比较仍然有意义。在Java中,new Integer(5).equals(new Integer(5))
的计算结果为true,5==5
也是如此。
我知道这不是一个非常技术上正确的答案,但我希望从Java背景来理解dart数字的行为仍然有用。