Sto provando a scrivere una funzione che confronta due elenchi di comparabili. I comparables possono essere di vari tipi purché gli elementi nelle stesse posizioni nelle due liste da confrontare siano confrontabili. Esempio:Confronto di elenchi comparabili in Kotlin
val list1 = ArrayList<Comparable<*>>()
val list2 = ArrayList<Comparable<*>>()
list1.add(10)
list1.add("xyz")
list1.add('a')
list2.add(10)
list2.add("xyz")
list2.add('b')
println(compare(list1, list2))
Questo dovrebbe stampare -1 perché
- 10 == 10
- "xyz" == "xyz"
- 'a' < 'b'
e quindi lista1 < lista2.
Ecco il codice che ho messo insieme con un po 'di un processo di tentativi ed errori visto che sono un po' confuso su come farmaci generici funzionano in questo caso specifico:
fun <T> compare(list1: List<Comparable<T>>, list2: List<Comparable<T>>): Int {
for (i in 0..Math.max(list1.size, list2.size) - 1) {
val elem1 = if (i < list1.size) list1[i] else null
val elem2 = if (i < list2.size) list2[i] else null
if (elem1 == null && elem2 == null)
return 0
if (elem1 == null)
return -1
if (elem2 == null)
return 1
@Suppress("UNCHECKED_CAST")
val comparisonResult = elem1.compareTo(elem2 as T)
if (comparisonResult != 0)
return comparisonResult
}
return 0
}
E questo in realtà si compila e funziona come previsto, ma ci sono alcune cose di cui sono perplesso.
Il mio primo tentativo è stato con la seguente firma del metodo:
fun compare(list1: List<Comparable<*>>, list2: List<Comparable<*>>): Int
Questo non ha però compilare. Perché? E come si differenzia questa dichiarazione dall'altra?
In secondo luogo, se provo a confrontare elenchi con valori incomparabili nelle posizioni corrispondenti, viene visualizzato un errore di tipo cast. Ad esempio, quando si confrontano [1,1] a [1, "abc"], ottengo
java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer
Questo si pone apparentemente tipo colato in
elem1.compareTo(elem2 as T)
cosa mi lascia perplesso: Come è il T risolto con Intero qui? In effetti, sono sorpreso che questo in realtà compili.
E terzo, c'è un modo per sbarazzarsi del cast incontrollato? Ho provato
if (elem2 !is T)
// throw Exception
ma che non è stato compilato. Perché? Sembra che in qualche modo si sappia che T è pensato per essere un numero intero in questa iterazione, quindi perché non riesco a digitare il controllo su di esso?
Grazie mille, Ilya, per la spiegazione dettagliata e una soluzione più elegante. Molto utile! –