【问题标题】:Create EnumMap from List of values in Kotlin从 Kotlin 中的值列表创建 EnumMap
【发布时间】:2018-06-21 18:07:09
【问题描述】:

我想定义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)) }
}

【问题讨论】:

    标签: kotlin kotlin-extension enum-map


    【解决方案1】:

    我认为您缺少的主要是 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))
    

    您还必须在此处指定键的类型,因为您不能有一个显式的泛型类型参数,然后是另一个隐式的类型参数。但我认为这是非常好的语法,因为您可以看到您正在创建的映射的键和值类型。

    【讨论】:

      【解决方案2】:

      作为从@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))
      

      【讨论】:

        【解决方案3】:

        在枚举本身中: private val shoeMap by lazy { values().associateBy { it.title } }

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-07-29
          • 2018-01-31
          • 1970-01-01
          • 2018-05-29
          • 1970-01-01
          • 1970-01-01
          • 2019-10-24
          • 2018-07-25
          相关资源
          最近更新 更多