2017-04-17 75 views
1

嘗試使用泛型類,但得到了下面的問題,那就是:科特林泛型超/子類

類型不匹配:推斷類型是ChildClassSuperClass<SuperType>預計

open class SuperClass<T> where T: SuperType { 
    fun modifySomething(input: T): T { 
     input.someValue.inc() 
     return input 
    } 
} 

open class SuperType { 
    val someValue: Int = 0 
} 

class ChildClass : SuperClass<ChildType>() 

class ChildType: SuperType() { 
    fun getModifiedValue(): Int { 
     return someValue 
    } 
} 

class TestEnvironment { 
    fun testType(superClass: SuperClass<SuperType>) { 
     // do something with superClass 
    } 

    fun itDoesntWork() { 
     testType(ChildClass()) // compilation error 
    } 
} 

這裏是the gistthe kotlin playground

所需結果LT是功能testType(superClass: SuperClass<SuperType>)應該接受類ChildClass()不使用通配符*

+0

請在問題本身的代碼。 – nhaarman

回答

1

這是generics variance,防止您的代碼工作。 SuperClass被定義爲

open class SuperClass<T> where T: SuperType { ... } 

,其類型參數T被聲明爲不變的(它沒有outin改性劑)。因此,分型的關係如下:

  • DerivedClass<ChildType>SuperClass<SuperType>
  • SuperClass<ChildType>亞型是SuperClass<SuperType>
  • DerivedClass<SuperType>亞型是SuperClass<SuperType>亞型。

由於函數的參數應該屬於參數類型的子類型,ChildClass實際上是DerivedClass<ChildType>,你不能傳遞ChildClass作爲SuperClass<SuperType>

您可以通過添加out projection參數類型的testType解決這個問題:

fun testType(superClass: SuperClass<out SuperType>) 

這基本上意味着,這個函數接受SuperClass<T>其中TSuperType一個亞型。當然,它在superClass用法上增加了一些限制:因爲T可以是絕對的任何子類型SuperType,因此將任何內容都傳遞給期望T作爲參數的函數是不安全的,這是禁止的。

另外,看到另一種答案,解釋爲不變仿製藥的行爲的原因:(link)