2016-06-05 18 views
6

La seguente non funziona, ma aiuta spera si capisce cosa voglio dire:Esiste un modo per richiedere che un tipo generico sia una classe dati in Kotlin?

class Example<T : DataClass> 

Nel caso in cui si vorrebbe sapere che cosa sto provando a realizzare, questo è un esempio di quello che avevo in mente:

class Repository<T> where T : Entity, // Entity defines mutable property 'id' 
          T : DataClass { 

    // assume there is a map here 

    fun add(obj: T) { 
    val copy = obj.copy(id = generateID()) 
    map.put(copy.id, copy) 
    } 

} 

Oppure c'è un modo migliore per realizzare ciò che sto cercando di fare?

risposta

4

Ho la sensazione che ciò che realmente volete sia che T possa essere in grado di copiare se stesso con un nuovo ID e avere un ID. Non necessariamente che si tratta di una classe di dati. Quindi potresti semplicemente usare un'interfaccia per definirlo.

Ad esempio:

interface CopyableWithId<out T> where T: CopyableWithId<T> { 
    fun copy(newId: Long): T 
    val id: Long 
} 

data class BarBaz(override var id: Long, var name: String): CopyableWithId<BarBaz> { 
    override fun copy(newId: Long): BarBaz = copy(id = newId) 
} 

class Repository<T> where T : CopyableWithId<T>{ 

    val map: MutableMap<Long, CopyableWithId<T>> = HashMap() 

    fun add(obj: T) { 
     val copy = obj.copy(generateID()) 
     map.put(copy.id, copy) 
    } 

    private fun generateID(): Long { 
     return 1L 
    } 
} 
1

No, data Le classi non hanno alcuna rappresentazione specifica nel sistema di tipi e non possono essere distinte dalle classi regolari (similar question).

È tuttavia possibile richiedere i metodi a una classe data con un determinato numero di componenti che utilizza un'interfaccia (in realtà sarà un'interfaccia marker sulle classi data).

Ecco un esempio per data classi con due componenti:

interface Data2<T1, T2> { 
    operator fun component1(): T1 
    operator fun component2(): T2 
    fun copy(t1: T1, t2: T2): Data2<T1, T2> 
} 

toString, hashCode e equals può essere chiamato su qualsiasi tipo comunque.

Poi basta contrassegnare la classe data con l'interfaccia:

data class Impl(val i: Int, val s: String): Data2<Int, String> 

val d: Data2<Int, String> = Impl(1, "2") 
val (c1, c2) = d 
val copy = d.copy(-1, d.component2()) 

copy funzione non è di tipo-safe completamente a causa Kotlin doesn't have self type (e non c'è modo di richiedere implementazioni di interfacce di essere sottotipo di un tipo specifico), ma se contrassegni solo le tue classi data, dovrebbe funzionare (vedi un'altra opzione sotto).

Un altro svantaggio è che si perde parametri di default di copy metodo e dovuto chiamare con tutti i parametri specificati:

val d = myD2.copy(newValue, myD2.component2()) 

Un'altra opzione è quella di definire queste interfacce come Data2<T1, T2, out Self>, class Impl(...): Data2<..., Impl>, e make copy restituisce Self, ma non lo renderà migliore se si utilizza l'interfaccia come Data2<SomeType, SomeType, *>.

Problemi correlati