27

遵循JEP 286:局部变量类型推断描述

我想知道,引入这种限制的原因是什么,例如:

Main.java:199: error: cannot infer type for local variable k

    var k = { 1 , 2 };
        ^   
(array initializer needs an explicit target-type)

所以对我来说逻辑上应该是:

var k = {1, 2}; // Infers int[]
var l = {1, 2L, 3}; // Infers long[]

因为 Java 编译器已经可以正确推断出数组的类型:

void decide() {
    arr(1, 2, 3);  // call  void arr(int ...arr)
    arr(1, 2L, 3); // call  void arr(long ...arr)
}

void arr(int ...arr) {
}

void arr(long ...arr) {
}

那么障碍是什么?

4

2 回答 2

33

每次我们提高 Java 中类型推断的范围时,我们都会收到一连串的“但你也可以推断出这个,​​为什么不呢?” (或者有时,不太礼貌。)

关于设计类型推理方案的一些一般性观察:

  • 推理方案总是有限制的;总有一些情况我们无法推断出答案,或者最终推断出令人惊讶的事情。我们越努力推断一切,就越有可能推断出令人惊讶的事情。这并不总是最好的权衡。
  • 很容易挑选“但在这种情况下你肯定可以推断”的例子。但是,如果这种情况与其他没有明显答案的情况非常相似,我们只是将问题转移了——“为什么它适用于 X 而不是 Y,其中 X 和 Y 都是 Z?”
  • 推理方案总是可以用来处理增量情况,但几乎总是有附带损害,要么是在其他情况下得到更糟糕的结果,要么增加不稳定性(看似不相关的更改可能会改变推断的类型),或者更复杂. 您不想仅针对可以推断的案例数量进行优化;您还想优化受过教育的用户预测什么可行,什么不可行的能力。绘制更简单的线条(例如,不要费心去推断数组初始化器的类型)通常是一种胜利。
  • 鉴于总是有限制,通常最好选择一个更小但定义更好的目标,因为这样可以简化用户模型。(请参阅有关“为什么我不能对私有方法的返回类型使用类型推断”的相关问题。答案是我们可以这样做,但结果将是一个更复杂的用户模型,以减少表达上的好处。我们称之为“复杂性回报率低。”)
于 2018-03-06T19:26:34.800 回答
23

从邮件列表 platform-jep-discuss 中,Brian Goetz为星期四(2016 年 3 月 10 日星期四 15:07:54 UTC)发送消息阅读器邮袋:

  1. 为什么初始化器是数组初始化器时不能使用 var ,如下所示:

    var ints = { 1, 2, 3 }
    

规则是:我们通过将初始值设定项视为独立表达式并推导其类型来推导变量的类型。然而,数组初始值设定项,如 lambda 和方法 ref,是poly 表达式 ——它们需要一个目标类型来计算它们的类型。所以他们被拒绝了。

我们可以完成这项工作吗?我们可能可以。但这会增加该功能的许多复杂性,以利于大多数极端情况。我们希望这是一个简单的功能。

简写数组初始值设定项从声明中获取其类型信息,但由于这里的声明var必须明确指定。

您将需要选择:

var k = new int[]{ 1 , 2 };

或者

int[] k = { 1 , 2 };

允许var k = { 1 , 2 }会改变已经是语法糖的东西的语义。在这种情况下,int[] n = { 1, 2 }类型是由声明决定的。如果你允许var n = { 1, 2 }类型是由初始化器本身突然确定的。这可能会导致(更容易创建)编译器错误或歧义。

于 2018-03-06T15:25:56.513 回答