Почему сопоставление ValueSet перечисления Scala не меняет тип значений?

Я обнаружил некоторое загадочное поведение в 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 в список перед сопоставлением значений?


person Sam    schedule 24.05.2014    source источник


Ответы (1)


MyEnum.values возвращает Enumeration.ValueSet. ValueSet подтипов 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)
person wingedsubmariner    schedule 24.05.2014
comment
В вашем примере вы хотели показать, что toList не нужно. - person som-snytt; 24.05.2014
comment
@som-snytt Ой. Отредактировано. - person wingedsubmariner; 24.05.2014