2016-02-16 37 views
6

Sto cercando di scrivere del codice generico, ma non riesco a eliminare l'errore Type of 'PROPERTY' is not a subtype of the overridden property.Kotlin: sostituisce la proprietà generica nel sottotipo

versione semplificata del mio codice:

abstract class BaseP<V> { 
    var view: V? = null 
} 

abstract class BaseF { 
    fun smth() { 
     pp.view = this 
    } 
    abstract val pp: BaseP<BaseF> 
} 

abstract class SubF: BaseF() { 
    abstract override val pp: BaseP<SubF> 
    // Error:(20, 30) Type of 'pp' is not a subtype of the overridden property 'public abstract val pp: BaseP<BaseF> defined in BaseF' 
} 

ho trovato che l'errore può essere @Suppress -ed, ma dubito che sia migliore e unico modo. C'è qualcosa di meglio?

E dopotutto non riesco a capire, perché subtypeA<subtypeB> non conta come sottotipo di baseA<baseB>, qualcuno può spiegarlo?

+0

quale riga genera l'errore? – voddan

risposta

7

Primo, SubtypeA<B> è un sottotipo di BaseA<B>, quindi il problema è nei sottotipi dei parametri generici.

La risposta è Kotlin generics variance, che è simile a that of Java.

Perché il numero SubtypeA<SubtypeB> non è considerato come sottotipo di BaseA<BaseB>?

I generici sono invarianti per default, il che significa che, anche nel caso più semplice, per una classe A<T>, A<SubtypeB> e A<BaseB> non sono sottotipi di ogni altro se non diversamente specificato da modificatori varianza in e out (o Java wildcards) .

Sono possibili due casi:

  • Se si desidera solo prendereT casi di istanze della vostra classe A, quindi è possibile utilizzare il modificatore out: A<out T>.

    Qui A<SubtypeB> diventa un sottotipo di A<BaseB>, poiché da A<SubtypeB> è possibile ovviamente prendere istanze di BaseB e non viceversa.

  • Se si desidera solo passaggioT nei vostri metodi di classe, quindi utilizzare in modificatore nella dichiarazione di classe: A<in T>.

    E qui A<BaseB> è un sottotipo di A<SubtypeB>, perché ogni istanza di A<BaseB> può anche ricevere SubtypeB nei metodi, ma non viceversa.

Se entrambi passate e prendere T da/per la classe A<T>, quindi l'unica opzione per T è di essere invariante, in modo che né A<SubB>A<SuperB> sono sottotipi di A<B>: altrimenti porterebbe a una contraddizione a quanto sopra

e questo è esattamente il caso: nel vostro BaseP<B>, si sono entrambi prendendo elementi di V e mettere quelli in view proprietà, in modo V può essere solo invariante, e BaseP<SubF> non è un sottotipo di BaseP<BaseF>, nessuno dei due è SubP<SubF>.