Dart int 和 double 被实习?由相同的()特别对待?

Pat*_*lin 5 identity equality object-identity dart

Dart 有两个:

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

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

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

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

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

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

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

Flo*_*sch 5

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

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

期望:用户期望数字相同。x == y(对于两个整数)但不相同(x,y)与常识背道而驰。

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

效率:虚拟机希望在任何可能的地方对数字进行拆箱。例如,在一个方法中,doubles 经常被移动到寄存器中。但是,跟踪原始盒子可能既麻烦又困难。

foo(x, y) {
  var result = x;
  while(y-- > 0) {
    result += x;
  }
  return result;
}
Run Code Online (Sandbox Code Playgroud)

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

var x = 5.0;
identical(x, foo(x, 0));  // should be true.
Run Code Online (Sandbox Code Playgroud)

如果虚拟机的拆箱result的方法变量foo就需要分配一个保鲜盒的result和identical因此调用将返回false。

通过修改定义,identical可以避免所有这些问题。但是,它会带来一小笔费用identical。


Pat*_*lin 3

看来我发帖太快了。我刚刚偶然发现了 Dart Issue 13084:规范说相同(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: ...
Run Code Online (Sandbox Code Playgroud)

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