【问题标题】:kotlin - which/how a collection able to store multiple data type?kotlin - 哪个/如何能够存储多种数据类型的集合?
【发布时间】:2021-03-06 19:51:42
【问题描述】:

我有两个不同的数据类,例如: 吉他和钢琴。

我想创建一个列表来存储这两个数据类,例如:仪器, 这样我就可以通过以下方式将两个数据类添加到列表中:

instruments.add(Guitar())
instruments.add(Piano())

我正在考虑使用:

val instruments = arrayListOf<Any>()

我的问题是实现这一目标的更好方法吗?

【问题讨论】:

  • 如果你放不同类型的数据,你会失去类型安全,这些类是否有一个共同的接口,如果有,你可以使用吗?
  • @Animesh Sahu,对不起,我不明白你的意思。这些数据确实有一些共同的属性,但并不多。但两者属于同一类别,例如我在问题中所说的。
  • 只需创建抽象类/接口并扩展/实现它。说abstract class MusicIntstrument(),然后说class Guitar : MusicIntstrument()。然后将列表初始化为arrayListOf&lt;MusicInstrument&gt;()

标签: android kotlin collections


【解决方案1】:

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

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-02-23
  • 1970-01-01
  • 2017-01-01
  • 2019-07-23
  • 2023-01-28
  • 1970-01-01
相关资源
最近更新 更多