2017-11-17 101 views
0

我有以下的使用Vavr的Java代碼片段。類型檢查失敗,除非我內聯一個參數。Javac不能推斷類型,除非lambda表達式被內聯

爲什麼下面的代碼不能被編譯器接受?

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上的文檔的鏈接相同:

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

回答

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的。因此,如果您試圖從map獲取東西,則會得到ClassCastException

// 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) { ... } 
+0

哦,對了,這是'''不兼容的不等式約束:(?延伸A,A)'''不'''不兼容的不等式約束:( ?擴展A,?擴展A)'''。非常感謝! – Zaaier