从Kotlin中的值列表创建EnumMap

时间:2018-06-21 18:07:10

标签: kotlin kotlin-extension enum-map

我想定义enum class的扩展名,该扩展名以与枚举常量相同的顺序接受值列表并输出EnumMap

我能够做的是使用来自List<V>的键数组作为输入来创建和扩展Enum<K>.values()对象。

似乎困难在于enum class本身不是具有.values()方法的对象。所以也许我的要求不明智。

这是使用列表扩展方法的有效示例。

import java.util.*

enum class Shoes(
    val title: String,
    val weight: Double) {
    WORKBOOT("tough", 11.0),
    SNEAKER("fast", 6.0),
    SLIPPER("soft", 3.0);
}

fun main(args: Array<String>) {
    val prices= listOf(11.5,8.2,3.5)
    val map = prices.enumMapOf(Shoes.values())
    map.print()
}

inline fun <reified K : Enum<K>, V> List<V>.enumMapOf(keys:Array<K>): EnumMap<K, V> {
    val map = EnumMap<K, V>(K::class.java)
    keys.forEachIndexed{i,k-> map[k]=this[i]}
    return map
}

fun <K:Enum<K>,V> EnumMap<K,V>.print() {
    this.forEach{k,v-> println("%d: %s --> %.2f".format(k.ordinal,k.name,v)) }
}

3 个答案:

答案 0 :(得分:5)

我认为您最缺少的是可以为您提供通用枚举值的enumValues方法。

这将允许您执行此操作(我也重新排列了创建EnumMap的代码,如果这看起来太复杂,则可以坚持使用自己的解决方案):

inline fun <reified K : Enum<K>, V> Enum<K>.mappedTo(values: List<V>): EnumMap<K, V> {
    return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}

当然,现在的问题是调用语法-必须在枚举的实例上 这样调用该函数:

Shoes.WORKBOOT.mappedTo(listOf(11.5, 8.2, 3.5))

这没有什么意义。进行此通话会更好:

Shoes.mappedTo(listOf(11.5, 8.2, 3.5))

但是据我所知,没有办法实现这种语法,因为您不能向通用枚举的伴随对象添加扩展,然后期望在特定枚举的伴随对象上调用它-不会那样互相继承。

因此,也许不用创建扩展名,而是可以使用常规函数,并从通用参数而不是接收者中获取枚举的类型:

inline fun <reified K : Enum<K>, V> mapEnumTo(values: List<V>): EnumMap<K, V> {
    return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
}

mapEnumTo<Shoes, Double>(listOf(11.5, 8.2, 3.5))

您还必须在这里指定键的类型,因为您不能有一个显式的泛型类型参数,然后是一个隐式的泛型类型参数。但是我认为这是一种非常不错的语法,因为您会看到正在创建的地图的键和值类型。

答案 1 :(得分:5)

作为一种从@ zsmb13的答案中消除显式Double的变通方法,您可以借用标准的Scala技巧,将其拆分为两个带有单独类型参数列表的方法调用,其中一个是显式的,另一个是推断的:

interface EnumMapper<K : Enum<K>> {
    operator fun <V> invoke(values: List<V>): EnumMap<K, V>
}

inline fun <reified K : Enum<K>> mapEnumTo() = object : EnumMapper<K> {
    override operator fun <V> invoke(values: List<V>): EnumMap<K, V> {
        return enumValues<K>().zip(values).toMap(EnumMap(K::class.java))
    }
}

mapEnumTo<Shoes>()(listOf(11.5, 8.2, 3.5))

答案 2 :(得分:-1)

在枚举本身中: 私有val shoeMap,由lazy {values()。associateBy {it.title}}