我正试图找到在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]
}
}
}
Run Code Online (Sandbox Code Playgroud)
我的问题是,这是最好的方法吗,还是有更好的方法?如果我有几个遵循类似模式的枚举怎么办?在Kotlin中是否有一种方法可以使这些代码在枚举中更易于使用?
JB *_*zet 152
首先,fromInt()的参数应该是Int,而不是Int?.尝试使用null获取Type显然会导致null,并且调用者甚至不应该尝试这样做.地图也没有理由变得可变.代码可以减少到
companion object {
private val map = Type.values().associateBy(Type::value)
fun fromInt(type: Int) = map[type]
}
Run Code Online (Sandbox Code Playgroud)
那段代码太短了,坦率地说,我不确定是否值得尝试找到一个可重用的解决方案.
vod*_*dan 25
在这种情况下没有多大意义,但这是@ 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
Run Code Online (Sandbox Code Playgroud)
一般情况下,伴随对象可以重用它们(与Java类中的静态成员不同)
hum*_*zed 24
我们可以使用find它,如果没有这样的元素被找到,返回的第一个元素匹配给定的谓词,或者为null.
companion object {
fun valueOf(value: Int): Type? = Type.values().find { it.value == value }
}
Run Code Online (Sandbox Code Playgroud)
squ*_*rel 14
如果您有很多枚举,这可能会节省一些击键次数:
inline fun <reified T : Enum<T>, V> ((T) -> V).find(value: V): T? {
return enumValues<T>().firstOrNull { this(it) == value }
}
Run Code Online (Sandbox Code Playgroud)
像这样使用它:
enum class Algorithms(val string: String) {
Sha1("SHA-1"),
Sha256("SHA-256"),
}
fun main() = println(
Algorithms::string.find("SHA-256")
?: throw IllegalArgumentException("Bad algorithm string: SHA-256")
)
Run Code Online (Sandbox Code Playgroud)
这将打印Sha256
可以认为更“惯用”的另一种选择是:
companion object {
private val map = Type.values().associateBy(Type::value)
operator fun get(value: Int) = map[value]
}
Run Code Online (Sandbox Code Playgroud)
然后可以像这样使用Type[type]。
我发现自己通过自定义,手动编码,值几次进行反向查找,并采用以下方法.
让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
}
Run Code Online (Sandbox Code Playgroud)
这个接口(不管名称是多么奇怪:))将某个值标记为显式代码.目标是能够写:
val a = Alphabet::class.decode(1) //Alphabet.A
val d = Alphabet::class.tryDecode(4) //null
Run Code Online (Sandbox Code Playgroud)
使用以下代码可以轻松实现:
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)
Run Code Online (Sandbox Code Playgroud)
另一个示例实现。OPEN如果没有输入匹配没有枚举选项,这也会设置默认值(此处为):
enum class Status(val status: Int) {
OPEN(1),
CLOSED(2);
companion object {
@JvmStatic
fun fromInt(status: Int): Status =
values().find { value -> value.status == status } ?: OPEN
}
Run Code Online (Sandbox Code Playgroud)
}
| 归档时间: |
|
| 查看次数: |
24316 次 |
| 最近记录: |