Kotlin 不支持多类型。但是,您可以应用变通方法。
首先,为了帮助建模您的问题,您可以按照 cmets 中的建议创建一个超类型(接口或抽象类),以提取公共属性,或者只使用一个“标记”接口。它允许将接受的对象缩小到某个类别,并改善控制。
无论如何,您可以使用filterIsInstance 过滤任何列表以仅返回所需类型的值:
enum class InstrumentFamily {
Strings, Keyboards, Winds, Percussions
}
abstract class Instrument(val family : InstrumentFamily)
data class Guitar(val stringCount : Int) : Instrument(InstrumentFamily.Strings)
data class Piano(val year: Int) : Instrument(InstrumentFamily.Keyboards)
fun main() {
val mix = listOf(Guitar(6), Piano(1960), null, Guitar(7), Piano(2010))
val guitars: List<Guitar> = mix.filterIsInstance<Guitar>()
guitars.forEach { println(it) }
val pianos : List<Piano> = mix.filterIsInstance<Piano>()
pianos.forEach { println(it) }
}
但是,请注意此运算符将扫描所有列表,因此如果与大型列表或多次使用它可能会变慢。所以,不要太依赖它。
另一种解决方法是为每种类型创建一个索引,并使用密封类来确保完全控制可能的类型(但因此,您将失去可扩展性能力)。
示例:
import kotlin.reflect.KClass
enum class InstrumentFamily {
Strings, Keyboards, Winds, Percussions
}
sealed class Instrument(val family : InstrumentFamily)
data class Guitar(val stringCount : Int) : Instrument(InstrumentFamily.Strings)
data class Piano(val year: Int) : Instrument(InstrumentFamily.Keyboards)
/** Custom mapping by value type */
class InstrumentContainer(private val valuesByType : MutableMap<KClass<out Instrument>, List<Instrument>> = mutableMapOf()) : Map<KClass<out Instrument>, List<Instrument>> by valuesByType {
/** When receiving an instrument, store it in a sublist specialized for its type */
fun add(instrument: Instrument) {
valuesByType.merge(instrument::class, listOf(instrument)) { l1, l2 -> l1 + l2}
}
/** Retrieve all objects stored for a given subtype */
inline fun <reified I :Instrument> get() = get(I::class) as List<out I>
}
fun main() {
val mix = listOf(Guitar(6), Piano(1960), null, Guitar(7), Piano(2010))
val container = InstrumentContainer()
mix.forEach { if (it != null) container.add(it) }
container.get<Guitar>().forEach { println(it) }
}