5

Dart 兼具:

  • 一个相等运算符==
  • 一个名为 的顶级函数identical()

通过语法的选择,想要==更频繁地使用 Dart 的运算符感觉很自然identical(),我喜欢这样。事实上,Idiomatic Dart的平等部分指出“在实践中,你很少需要使用” 。identical()

在最近对我的一个关于自定义过滤器的问题的回答中,似乎Angular Dart更倾向于使用,identical()而不是==在尝试确定模型的更改是否已达到稳定状态时。(我认为,出于效率的原因,这对于大型模型是有意义的。)

这让我开始思考int's 的身份,所以我写了一些identical()over ints 的测试。虽然我预计 small ints可能是“interned/cached”(例如类似于JavaInteger.valueOf()所做的),但令我惊讶的是,我似乎无法生成两个int相等但不相同的 s。我得到了类似的结果double

int和值是否double被保留/缓存?或者也许identical()是特别对待他们?来自 Java 背景,我曾经等同于 Dart 的:

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

但现在这似乎是错误的。有谁知道发生了什么?

4

3 回答 3

5

数字被特殊对待。如果它们的位模式相同,则它们必须相同(尽管这是否包括不同版本的 NaN 仍然存在争议)。

主要原因是期望、内部细节和效率的泄露。

期望:用户期望数字相同。x == y(对于两个整数)但不相同(x,y)违反常识。

内部细节泄露:VM 使用 SMI(SMall Integers)来表示特定范围内的整数(32 位机器上为 31 位,64 位机器上为 63 位)。这些是规范化的并且总是相同的。根据您运行的平台,公开此内部实现细节会导致结果不一致。

效率:VM 想尽可能地拆箱号码。例如,在方法内部,双精度数经常被移动到寄存器中。但是,跟踪原始盒子可能既麻烦又困难。

foo(x, y) {
  var result = x;
  while(y-- > 0) {
    result += x;
  }
  return result;
}

假设 VM 优化此功能并result移入寄存器(在此过程中拆箱x)。这允许一个紧密的循环,result然后有效地修改。困难的情况发生,当y为 0。循环不会执行,foox直接返回。换句话说,以下内容必须为真:

var x = 5.0;
identical(x, foo(x, 0));  // should be true.

如果 VMresult在方法中对变量进行拆箱,foo则需要为 分配一个新的框,result因此identical调用将返回false

通过修改定义,identical所有这些问题都被避免了。identical不过,支票的成本很低。

于 2014-01-28T08:57:53.630 回答
3

好像我发的太快了。我刚刚偶然发现 Dart 问题13084: Spec says same(1.0, 1) 是真的,即使它们有不同的类型,这导致我进入语言规范的对象标识的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: ...

还有更多处理列表、映射和常量对象的子句。有关完整的详细信息,请参阅语言规范。因此,identical()它不仅仅是一个简单的引用相等性测试。

于 2014-01-27T20:47:45.053 回答
1

我不记得它的来源,但在 dartlang.org 或问题跟踪器上的某个地方据说numint并且double确实得到了特殊处理。这些特殊处理之一是您不能出于性能原因对这些类型进行子类化,但可能还有更多。这种特殊处理究竟意味着什么,可能只能由开发人员来回答,或者也许只有熟读规范的人才能回答,但可以推断出一件事:

数字类型是 dart 对象——它们有你可以在它们的实例上调用的方法。但是它们也具有原始数据类型的特性,就像你可以做的那样int i = 3;,而纯对象应该在new某处有一个关键字。这与 Java 不同,Java 有真正的原始类型和包装它们并公开实例方法的真实对象。

虽然技术细节肯定更复杂,但如果您将 dart 数字视为对象和基元的混合体,那么您与 Java 的比较仍然是有道理的。在 Java 中,new Integer(5).equals(new Integer(5))计算结果为真,5==5.

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

于 2014-01-27T20:45:20.890 回答