除非内联 lambda 表达式,否则 Javac 无法推断类型
Javac can't infer type unless lambda expression is inlined
我有以下使用 Vavr 的 Java 代码片段。除非我内联一个参数,否则类型检查会失败。
为什么下面的代码不能被编译器接受?
import io.vavr.Function1;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.collection.List;
import io.vavr.Option;
import static io.vavr.collection.List.unfoldRight;
class A {}
class B {}
class Main {
Function1<A, Option<Tuple2<B, A>>> f = (a) -> Option.of(Tuple.of(new B(), new A()));
List<B> L0 = unfoldRight(new A(), f); // *
List<B> L1 = unfoldRight(new A(), (a) -> Option.of(Tuple.of(new B(), new A()));
Option<Tuple2<B, A>> g(A a) { return Option.of(Tuple.of(new B(), new A())); }
List<B> L2 = unfoldRight(new A(), (a) -> g(a)); // **
}
// * Compilation fails with: "Incompatible equality constraint: ? extends T and A"
// ** Compilation fails with: "Incompatible equality constraint: ? extends A and A"
这是 Vavr 库中 unfoldRight 的方法签名:
static <T, U> List<U> unfoldRight(T seed, Function<? super T, Option<Tuple2<? extends U, ? extends T>>> f)
这里是 link 的 Github 文档:
关键是 Option<Tuple<A, B>>
不是 Option<Tuple<? extends A, ? extends B>>
的实例(尽管它是 Option<? extends Tuple<? extends A, ? extends B>>
)。
考虑 List<Map<A, B>>
和 List<Map<? extends A, ? extends B>>
的情况(从类型安全的角度来看,这与您的代码相同)。如果你能写:
List<Map<A, B>> list = new ArrayList<>();
// Compiler error! Pretend it's OK, though.
List<Map<? extends A, ? extends B>> list2 = list;
Map<SubclassOfA, SubclassOfB> map = new HashMap<>();
list2.add(map);
list.get(0).put(new A(), new B());
现在这是个问题,因为 map
包含 key/value 对类型 A,B
,而不是 SubclassOfA,SubclassOfB
。因此,如果您尝试从 map
.
获取内容,您将得到 ClassCastException
// ClassCastException!
SubclassOfA soa = map.keySet().iterator().next();
因此,编译器不允许它。
如果list2
被声明为List<? extends Map<? extends A, ? extends B>>
,你不能调用list2.add(map)
,所以你不能得到同样的问题。因此,该分配将被允许。
为您的类型添加通配符上限:
Function1<A, Option<Tuple2<? extends B, ? extends A>>> f = ...
Option<Tuple2<? extends B, ? extends A>> g(A a) { ... }
我有以下使用 Vavr 的 Java 代码片段。除非我内联一个参数,否则类型检查会失败。
为什么下面的代码不能被编译器接受?
import io.vavr.Function1;
import io.vavr.Tuple;
import io.vavr.Tuple2;
import io.vavr.collection.List;
import io.vavr.Option;
import static io.vavr.collection.List.unfoldRight;
class A {}
class B {}
class Main {
Function1<A, Option<Tuple2<B, A>>> f = (a) -> Option.of(Tuple.of(new B(), new A()));
List<B> L0 = unfoldRight(new A(), f); // *
List<B> L1 = unfoldRight(new A(), (a) -> Option.of(Tuple.of(new B(), new A()));
Option<Tuple2<B, A>> g(A a) { return Option.of(Tuple.of(new B(), new A())); }
List<B> L2 = unfoldRight(new A(), (a) -> g(a)); // **
}
// * Compilation fails with: "Incompatible equality constraint: ? extends T and A"
// ** Compilation fails with: "Incompatible equality constraint: ? extends A and A"
这是 Vavr 库中 unfoldRight 的方法签名:
static <T, U> List<U> unfoldRight(T seed, Function<? super T, Option<Tuple2<? extends U, ? extends T>>> f)
这里是 link 的 Github 文档:
关键是 Option<Tuple<A, B>>
不是 Option<Tuple<? extends A, ? extends B>>
的实例(尽管它是 Option<? extends Tuple<? extends A, ? extends B>>
)。
考虑 List<Map<A, B>>
和 List<Map<? extends A, ? extends B>>
的情况(从类型安全的角度来看,这与您的代码相同)。如果你能写:
List<Map<A, B>> list = new ArrayList<>();
// Compiler error! Pretend it's OK, though.
List<Map<? extends A, ? extends B>> list2 = list;
Map<SubclassOfA, SubclassOfB> map = new HashMap<>();
list2.add(map);
list.get(0).put(new A(), new B());
现在这是个问题,因为 map
包含 key/value 对类型 A,B
,而不是 SubclassOfA,SubclassOfB
。因此,如果您尝试从 map
.
ClassCastException
// ClassCastException!
SubclassOfA soa = map.keySet().iterator().next();
因此,编译器不允许它。
如果list2
被声明为List<? extends Map<? extends A, ? extends B>>
,你不能调用list2.add(map)
,所以你不能得到同样的问题。因此,该分配将被允许。
为您的类型添加通配符上限:
Function1<A, Option<Tuple2<? extends B, ? extends A>>> f = ...
Option<Tuple2<? extends B, ? extends A>> g(A a) { ... }