首页 文章

Kotlin中有效的Enums反向查找?

提问于
浏览
68

我正试图找到在Kotlin上对枚举进行“反向查找”的最佳方法 . 我对Effective Java的一个看法是,你在枚举中引入了一个静态映射来处理反向查找 . 使用简单的枚举将其移植到Kotlin会导致我看到如下代码:

enum class Type(val value: Int) {
    A(1),
    B(2),
    C(3);

    companion object {
        val map: MutableMap<Int, Type> = HashMap()

        init {
            for (i in Type.values()) {
                map[i.value] = i
            } 
        }

        fun fromInt(type: Int?): Type? {
            return map[type]
        }
    }
}

我的问题是,这是最好的方法吗,还是有更好的方法?如果我有几个遵循类似模式的枚举怎么办?在Kotlin中是否有一种方法可以使这些代码在枚举中更易于使用?

5 回答

  • 6

    首先,fromInt()的参数应该是Int,而不是Int? . 尝试使用null获取Type显然会导致null,并且调用者甚至不应该尝试这样做 . Map 也没有理由变得可变 . 代码可以减少到

    companion object {
        private val map = Type.values().associateBy(Type::value)
        fun fromInt(type: Int) = map[type]
    }
    

    那段代码太短了,坦率地说,我不确定是否值得尝试找到一个可重用的解决方案 .

  • -3

    在这种情况下没有多大意义,但这是@ JBNized解决方案的“逻辑提取”:

    open class EnumCompanion<T, V>(private val valueMap: Map<T, V>) {
        fun fromInt(type: T) = valueMap[type]
    }
    
    enum class TT(val x: Int) {
        A(10),
        B(20),
        C(30);
    
        companion object : EnumCompanion<Int, TT>(TT.values().associateBy(TT::x))
    }
    
    //sorry I had to rename things for sanity
    

    一般情况下,伴随对象可以重用它们(与Java类中的静态成员不同)

  • 18

    我们可以使用find Returns the first element matching the given predicate, or null if no such element was found.

    companion object {
       fun valueOf(value: Int): Type? = Type.values().find { it.value == value }
    }
    
  • 18

    我发现自己通过自定义,手动编码,值几次进行反向查找,并采用以下方法 .

    使 enum 实现共享接口:

    interface Codified<out T : Serializable> {
        val code: T
    }
    
    enum class Alphabet(val value: Int) : Codified<Int> {
        A(1),
        B(2),
        C(3);
    
        override val code = value
    }
    

    这个接口(不管名称是多么奇怪:))将某个值标记为显式代码 . 目标是能够写:

    val a = Alphabet::class.decode(1) //Alphabet.A
    val d = Alphabet::class.tryDecode(4) //null
    

    使用以下代码可以轻松实现:

    interface Codified<out T : Serializable> {
        val code: T
    
        object Enums {
            private val enumCodesByClass = ConcurrentHashMap<Class<*>, Map<Serializable, Enum<*>>>()
    
            inline fun <reified T, TCode : Serializable> decode(code: TCode): T where T : Codified<TCode>, T : Enum<*> {
                return decode(T::class.java, code)
            }
    
            fun <T, TCode : Serializable> decode(enumClass: Class<T>, code: TCode): T where T : Codified<TCode> {
                return tryDecode(enumClass, code) ?: throw IllegalArgumentException("No $enumClass value with code == $code")
            }
    
            inline fun <reified T, TCode : Serializable> tryDecode(code: TCode): T? where T : Codified<TCode> {
                return tryDecode(T::class.java, code)
            }
    
            @Suppress("UNCHECKED_CAST")
            fun <T, TCode : Serializable> tryDecode(enumClass: Class<T>, code: TCode): T? where T : Codified<TCode> {
                val valuesForEnumClass = enumCodesByClass.getOrPut(enumClass as Class<Enum<*>>, {
                    enumClass.enumConstants.associateBy { (it as T).code }
                })
    
                return valuesForEnumClass[code] as T?
            }
        }
    }
    
    fun <T, TCode> KClass<T>.decode(code: TCode): T
            where T : Codified<TCode>, T : Enum<T>, TCode : Serializable 
            = Codified.Enums.decode(java, code)
    
    fun <T, TCode> KClass<T>.tryDecode(code: TCode): T?
            where T : Codified<TCode>, T : Enum<T>, TCode : Serializable
            = Codified.Enums.tryDecode(java, code)
    
  • 123

    val t = Type.values()[序数]

    :)

相关问题