“数组初始值设定项需要显式目标类型” - 为什么?

2022-09-01 15:20:56

遵循 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) {
}

那么障碍是什么呢?


答案 1

每当我们在Java中提高类型推断的范围时,我们都会得到一连串的“但你也可以推断出这一点,你为什么不呢?(或者有时,不那么礼貌。

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

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

答案 2

来自邮件列表平台-jep-discuss,消息读者邮件袋星期四(星期四3月10 15:07:54 UTC 2016)由Brian Goetz:

  1. 为什么当初始值设定项是数组初始值设定项时不能使用 var,如:

    var ints = { 1, 2, 3 }
    

规则是:通过将初始值设定项视为独立表达式并派生其类型来派生变量的类型。但是,数组初始值设定项(如 lambda 和方法 refs)是多元表达式 - 它们需要目标类型才能计算其类型。所以他们被拒绝了。

我们能做到这一点吗?我们也许可以。但它会给该功能增加很多复杂性,以利于大多数角落案例。我们希望这是一个简单的功能。

速记数组初始值设定项从声明中获取其类型信息,但正如此处的声明所示,必须显式指定它。var

您需要在以下选项中进行选择:

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

int[] k = { 1 , 2 };

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