1

我有以下使用 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 库中展开的方法签名:

static <T, U> List<U> unfoldRight(T seed, Function<? super T, Option<Tuple2<? extends U, ? extends T>>> f)

这里是 Github 文档的链接:

https://github.com/vavr-io/vavr/blob/master/vavr/src/main/java/io/vavr/collection/List.java#L644-L671

4

1 回答 1

3

关键是它Option<Tuple<A, B>>不是Option<Tuple<? extends A, ? extends B>>(尽管它是Option<? extends Tuple<? extends A, ? extends B>>)的一个实例。

考虑 a 的情况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();

Ideone demo

因此,编译器不允许这样做。

如果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) { ... }
于 2017-11-17T22:52:28.320 回答