解析字节流时Kotlin字节vs枚举

时间:2018-07-05 20:01:01

标签: kotlin

我正在尝试解析Kotlin中的字节流,其中模式是一系列opCode字节,后跟基于opCode的任意字节。因此,我首先建立了一个枚举,例如:

enum class OpCode(val code:Byte) {
    foo(1),
    bar(2),
    yak(3),
}

因此,当我构建解析循环时,我想编写类似以下内容的

while(stream.available() > 0) {
    val opCode = stream.read().toByte()
    when (opCode) {
        OpCode.foo.code -> { // do foo stuff }
        OpCode.bar.code -> { // do bar stuff }
        OpCode.yak.code -> { // do yak stuff }
    }
}

让我烦恼的是,我不得不不断地将.code放在那儿。我宁愿做类似的事情:

val opCode = OpCode(stream.read().toByte())

但是它告诉我无法实例化枚举实例。有没有更惯用的方式来做到这一点?

2 个答案:

答案 0 :(得分:2)

您可以向枚举添加伴侣,以添加用于查找相关枚举值的功能:

enum class OpCode(val code: Byte) {
    Foo(1),
    Bar(2),
    Yak(3);

    companion object {
        fun of(code: Byte) = values().find { it.code == code }
                ?: throw IllegalAccessException("")
    }
}

像这样使用:

while (stream.available() > 0) {
     val opCode = OpCode.of(stream.read().toByte())
     when (opCode) {
         OpCode.Foo -> {}
         OpCode.Bar -> {}
         OpCode.Yak -> {}
     }
 }

答案 1 :(得分:1)

@ s1m0nw1答案的替代方法,使搜索一次:

interface EnumCodesMap<E : Enum> {
    fun values(): Array<E>
    val codesMap = values().associate { it.code to it }
}

enum class OpCode(val code: Byte) {
    Foo(1),
    Bar(2),
    Yak(3);

    companion object : EnumCodesMap<OpCode>
}

...
val opCode = OpCode.codesMap[stream.read().toByte()]

请注意,此类内容无法内置,因为您可以使用相同的code具有多个值:

enum class OpCode(val code: Byte) {
    Foo(1),
    Bar(1)
}

编辑:您可以提取它以支持多个枚举,但是要有一些技巧:

inline fun <reified E : Enum<E>, K> EnumCodesMap(crossinline getKey: (E) -> K) = object : EnumCodesMap<E, K> {
    override val codesMap = enumValues<E>().associate { getKey(it) to it }
}

interface EnumCodesMap<E : Enum<E>, K> {
    val codesMap: Map<K, E>
}

enum class OpCode(val code: Byte) {
    Foo(1),
    Bar(2),
    Yak(3);

    companion object : EnumCodesMap<OpCode, Byte> by EnumCodesMap({ it.code })
}