2016-06-05 13 views
6

Następujące nie działa, ale mam nadzieję, że pomaga zrozumieć, co mam na myśli:Czy istnieje sposób na żądanie, aby typowy typ był klasą danych w Kotlin?

class Example<T : DataClass> 

W przypadku chcesz wiedzieć, co staram się osiągnąć, jest przykładem tego, co miałem na myśli:

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) 
    } 

} 

Czy istnieje lepszy sposób na wykonanie tego, co próbuję wykonać?

Odpowiedz

4

Mam wrażenie, że to, czego naprawdę chcesz, to że T powinno móc kopiować się z nowym ID i mieć ID. Niekoniecznie, że jest to klasa danych. Możesz więc użyć interfejsu, aby to zdefiniować.

Na przykład:

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

Nie, data klasy nie mają określonej reprezentacji w systemie typu i nie można ich odróżnić od klas regularnych (similar question).

Można jednak wymagać zastosowania metod klasy data z pewną liczbą komponentów przy użyciu interfejsu (w rzeczywistości będzie to interfejs znacznika w klasach data).

Oto przykład dla data klas z dwóch komponentów:

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

toString, hashCode i equals można nazwać na wszelkiego rodzaju tak.

Następnie wystarczy zaznaczyć swoją klasę data z interfejsem:

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 funkcja nie jest całkowicie wpisać bezpieczny ponieważ Kotlin doesn't have self type (i nie sposób wymagać implementacje interfejsu być podtypem określonego typu), ale jeśli oznaczysz je swoimi klasami data, powinno działać (zobacz inną opcję poniżej).

Inną wadą jest to, że można stracić domyślne parametry copy metody i trzeba nazwać ze wszystkimi parametrami określonymi:

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

Inną opcją jest określenie tych interfejsów jak Data2<T1, T2, out Self>, class Impl(...): Data2<..., Impl> i make copy return Self, ale nie zrobi to lepiej, jeśli użyjesz interfejsu jako Data2<SomeType, SomeType, *>.

Powiązane problemy