为什么映射Scala枚举的ValueSet不会更改值的类型?

时间:2014-05-24 03:19:13

标签: scala enumeration

我在Scala的ValueSet中发现了一些令人费解的行为。有了这样的枚举,

object MyEnum extends Enumeration{
    val V1 = new MyEnum
    val V2 = new MyEnum
    class MyEnum extends Val
    implicit def convertValue(v: Value): MyEnum = v.asInstanceOf[MyEnum]
}

将值MyEnum.values从Value映射到MyEnum会产生另一个ValueSet,当转换为数组时,它不会保留映射类型。

val naiveMappedValues = MyEnum.values.map(
    implicitly[MyEnum.Value => MyEnum.MyEnum]).toArray
// REPL prints: naiveMappedValues: Array[MyEnum.Value] = Array(V1, V2)

如果MyEnum.values首次转换为列表,则最终数组的类型是正确的。

val mappedValues = MyEnum.values.toList.map(
    implicitly[MyEnum.Value => MyEnum.MyEnum]).toArray
// REPL prints: mappedValues: Array[MyEnum.MyEnum] = Array(V1, V2)

为什么会这样?为什么在映射值之前首先将ValueSet转换为List?

1 个答案:

答案 0 :(得分:5)

MyEnum.values会返回Enumeration.ValueSetValueSet个子类型Set[Value]。当您在map上执行ValueSet时,它会尝试向您返回一个新的ValueSet,只要新元素是Value的子类型,它就可以执行此操作。但是,ValueSet始终为Set[Value],因此当元素向上转换回Value时,地图内的向下转换将被撤消。另一方面,List有一个类型参数,因此您可以将List[Value]映射到List[MyEnum]

所有这些魔法都由CanBuildFrom所需的map控制。如果您使用collection.breakOut,则可以强制map构建您想要的任何类型:

val fastMappedValues: Array[MyEnum.MyEnum] = MyEnum.values.map(
    implicitly[MyEnum.Value => MyEnum.MyEnum])(collection.breakOut)