我使用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)
这里是Github文档的链接:
答案 0 :(得分:1)
关键是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
包含A,B
类型的键/值对,而不是SubclassOfA,SubclassOfB
。因此,如果您尝试从ClassCastException
获取内容,则会获得map
。
// 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) { ... }