为什么此类型推断不适用于此Lambda表达式方案?

为什么此类型推断不适用于此Lambda表达式方案?,第1张

为什么此类型推断不适用于此Lambda表达式方案? 引擎盖下

使用一些隐藏的

javac
功能,我们可以获得有关正在发生的事情的更多信息:

$ javac -XDverboseResolution=deferred-inference,success,applicable LambdaInference.java LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.foo(value -> true).booleanValue(); // Compile error here       ^  phase: BASIC  with actuals: <none>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Object>)Object)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Foo.foo(value -> true).booleanValue(); // Compile error here^  instantiated signature: (Bar<Object>)Object  target-type: <none>  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: error: cannot find symbol    Foo.foo(value -> true).booleanValue(); // Compile error here    ^  symbol:   method booleanValue()  location: class Object1 error

这是很多信息,让我们对其进行分解。

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.foo(value -> true).booleanValue(); // Compile error here       ^  phase: BASIC  with actuals: <none>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Object>)Object)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)

阶段:方法适用性阶段
实际情况:在
类型参数中传递的实际参数:显式类型参数
候选项:可能适用的方法


实际情况是

<none>
因为我们的隐式lambda
与适用性无关。

编译器解决您的调用

foo
来命名的唯一方法
foo
Foo
。它已经部分实例化到
Foo.<Object> foo
(因为没有实际值或type-
args),但是可以在推论阶段改变。

LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Foo.foo(value -> true).booleanValue(); // Compile error here^  instantiated signature: (Bar<Object>)Object  target-type: <none>  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)

实例化签名:的完全实例化签名

foo
。这是此步骤的结果(此时,将不再对的签名进行类型推断
foo
)。
target-type:在其中进行调用的上下文。如果方法调用是分配的一部分,则它将在左侧。如果方法调用本身是方法调用的一部分,则它将是参数类型。

由于您的方法调用是悬空的,因此没有目标类型。由于没有目标类型,因此无法进行进一步的推断,

foo
T
推断为
Object


分析

编译器在推理期间不使用隐式类型的lambda。在某种程度上,这是有道理的。通常,给定的类型

param ->BODY
是您将无法编译。如果您确实尝试推断from
的类型,则可能会导致鸡和蛋的类型出现问题。在将来的Java版本中,可能对此进行一些改进。
BODY``param``param``BODY


解决方案

Foo.<Boolean> foo(value -> true)

此解决方案提供了一个显式类型参数

foo
(请注意以下
with type-args
部分)。这会将方法签名的部分实例化更改为
(Bar<Boolean>)Boolean
,这就是您想要的。

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.<Boolean> foo(value -> true).booleanValue(); // Compile error here       ^  phase: BASIC  with actuals: <none>  with type-args: Boolean  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Boolean>)Boolean)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: resolving method booleanValue in type Boolean to candidate 0    Foo.<Boolean> foo(value -> true).booleanValue(); // Compile error here   ^  phase: BASIC  with actuals: no arguments  with type-args: no arguments  candidates:      #0 applicable method found: booleanValue()

Foo.foo((Value<Boolean> value) -> true)

该解决方案显式地键入您的lambda,从而使其与适用性相关(请注意

withactuals
以下内容)。这会将方法签名的部分实例化更改为
(Bar<Boolean>)Boolean
,这就是您想要的。

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.foo((Value<Boolean> value) -> true).booleanValue(); // Compile error here       ^  phase: BASIC  with actuals: Bar<Boolean>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Boolean>)Boolean)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Foo.foo((Value<Boolean> value) -> true).booleanValue(); // Compile error here^  instantiated signature: (Bar<Boolean>)Boolean  target-type: <none>  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: resolving method booleanValue in type Boolean to candidate 0    Foo.foo((Value<Boolean> value) -> true).booleanValue(); // Compile error here          ^  phase: BASIC  with actuals: no arguments  with type-args: no arguments  candidates:      #0 applicable method found: booleanValue()

Foo.foo((Bar<Boolean>) value -> true)

与上述相同,但口味略有不同。

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.foo((Bar<Boolean>) value -> true).booleanValue(); // Compile error here       ^  phase: BASIC  with actuals: Bar<Boolean>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Boolean>)Boolean)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Foo.foo((Bar<Boolean>) value -> true).booleanValue(); // Compile error here^  instantiated signature: (Bar<Boolean>)Boolean  target-type: <none>  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: resolving method booleanValue in type Boolean to candidate 0    Foo.foo((Bar<Boolean>) value -> true).booleanValue(); // Compile error here        ^  phase: BASIC  with actuals: no arguments  with type-args: no arguments  candidates:      #0 applicable method found: booleanValue()

Boolean b = Foo.foo(value -> true)

该解决方案为您的方法调用提供了一个明确的目标(请参见

target-type
下文)。这使deferred-
instantiation可以推断应该使用type参数
Boolean
代替
Object
(请参见
instantiated signature
下文)。

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Boolean b = Foo.foo(value -> true);        ^  phase: BASIC  with actuals: <none>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Object>)Object)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Boolean b = Foo.foo(value -> true); ^  instantiated signature: (Bar<Boolean>)Boolean  target-type: Boolean  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)

免责声明

这是正在发生的行为。我不知道这是JLS中指定的内容。我可以四处挖掘,看看是否可以找到指定此行为的确切部分,但是类型推断符号使我头疼。

这也不能完全解释为什么更改

Bar
为使用原始格式
Value
可以解决此问题:

LambdaInference.java:16: Note: resolving method foo in type Foo to candidate 0    Foo.foo(value -> true).booleanValue();       ^  phase: BASIC  with actuals: <none>  with type-args: no arguments  candidates:      #0 applicable method found: <T>foo(Bar<T>)        (partially instantiated to: (Bar<Object>)Object)  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: Deferred instantiation of method <T>foo(Bar<T>)    Foo.foo(value -> true).booleanValue();^  instantiated signature: (Bar<Boolean>)Boolean  target-type: <none>  where T is a type-variable:    T extends Object declared in method <T>foo(Bar<T>)LambdaInference.java:16: Note: resolving method booleanValue in type Boolean to candidate 0    Foo.foo(value -> true).booleanValue();    ^  phase: BASIC  with actuals: no arguments  with type-args: no arguments  candidates:      #0 applicable method found: booleanValue()

出于某种原因,将其更改为使用原始

Value
格式将允许延迟的实例推断
T
Boolean
。如果我不得不推测的话,我可能会猜想,当编译器尝试将lambda适配到时
Bar<T>
,它可以通过查看lambda的主体来推断出这
T
一点
Boolean
。这意味着我先前的分析是不正确的。编译器
可以 对lambda主体执行类型推断,但只能对 出现在返回类型中的类型变量执行。



欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/zaji/4964159.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-11-13
下一篇2022-11-13

发表评论

登录后才能评论

评论列表(0条)

    保存