代码之家  ›  专栏  ›  技术社区  ›  Travis Griggs

解析字节流时的Kotlin字节与枚举

  •  0
  • Travis Griggs  · 技术社区  · 6 年前

    我试图解析kotlin中的字节流,其中模式是一系列操作码字节,后跟基于操作码的任意字节。所以我首先建立了一个枚举,比如:

    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 回复  |  直到 6 年前
        1
  •  1
  •   Alexey Romanov    6 年前

    @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 })
    }
    
        2
  •  2
  •   s1m0nw1    6 年前

    您可以向枚举添加一个同伴,以添加查找相关枚举值的功能:

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