Котлин байтов против перечислений при разборе потока байтов - PullRequest
0 голосов
/ 05 июля 2018

Я пытаюсь проанализировать поток байтов в Kotlin, где шаблон представляет собой серию байтов opCode, за которыми следуют произвольные байты, основанные на opCode. Итак, я начал с установки enum, что-то вроде:

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

Но это говорит мне, что я не могу создать экземпляр enum. Есть ли более идиоматический способ сделать это?

Ответы [ 2 ]

0 голосов
/ 05 июля 2018

Альтернатива ответу @ 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 })
}
0 голосов
/ 05 июля 2018

Вы можете добавить компаньона к вашему перечислению, чтобы добавить функциональность для поиска соответствующего значения перечисления:

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 -> {}
     }
 }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...