飞镖int和双被拘禁?特别是由相同的()处理?

时间:2014-01-27 20:26:32

标签: dart identity equality object-identity

达特有两个:

  • 等于运算符==
  • 名为identical()的顶级函数。

通过选择语法,想要比==更频繁地使用Dart的identical()运算符感觉很自然,我喜欢这样。事实上,Section on EqualityIdiomatic Dart表示“在实践中,您很少需要使用”identical()

在最近对one of my questions concerning custom filters的回答中,似乎 Angular Dart 赞成在尝试确定是否更改模型时使用identical()而不是==已达到稳定状态。 (出于效率的原因,我认为,对于大型模型,这是有道理的。)

这让我想到int的身份,所以我写了identical()int的一些测试。虽然我预计小int s 可能“实习/缓存”(例如类似于Java's Integer.valueOf()所做的事情),令我惊讶的是,我可以'似乎生成两个相等但不相同的int 。我得到double的类似结果。

intdouble值是否被实习/缓存?或者也许identical()特别对待他们?来自Java背景,我过去等同于Dart's:

  • ==到Java的equal()方法和
  • identical()到Java的等式测试==

但现在看来错了。有谁知道发生了什么事?

3 个答案:

答案 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或问题跟踪器的某个地方,据说numintdouble确实得到了特殊待遇。其中一种特殊处理方法是,出于性能原因,您不能将这些类型子类化,但可能还有更多。究竟这种特殊处理方法究竟是什么,可能只有开发人员才能回答,或者可能是那些熟悉规范的人,但有一点可以推断:

数字类型是dart对象 - 它们具有可以在其实例上调用的方法。但它们也具有原始数据类型的特性,因为您可以int i = 3;,而纯对象应该在某处具有new关键字。这与Java不同,Java中存在真实的原始类型和包装它们的真实对象并暴露实例方法。

虽然技术细节肯定更复杂,但如果你把dart数字看作是对象和原始的混合,你与Java的比较仍然有意义。在Java中,new Integer(5).equals(new Integer(5))的计算结果为true,5==5也是如此。

我知道这不是一个非常技术上正确的答案,但我希望从Java背景来理解dart数字的行为仍然有用。