Scala: выход из одного типа коллекции в другой

Относительно команды yield в Scala и следующем примере:

val values = Set(1, 2, 3)
val results = for {v <- values} yield (v * 2)

Может ли кто-нибудь объяснить, как Scala знает, к какому типу коллекции нужно уступить? Я знаю, что он основан на значениях, но как я могу писать код, который реплицирует выход? Есть ли способ изменить тип собираемой коллекции? В примере я хочу, чтобы результаты были типа List вместо Set. В противном случае, каков наилучший способ конвертировать из одной коллекции в другую? Я знаю об _: *, но поскольку Set не является Seq, это не работает. Самое лучшее, что я смог найти до сих пор, - результаты val listResults = List() ++.

Ps. Я знаю, что пример не соответствует рекомендуемому функциональному способу (который будет использовать карту), но это всего лишь пример.

Ответ 1

Понятия for переводятся компилятором на вызовы map/flatMap/filter, используя эту схему.

Этот отличный ответ Даниэля отвечает на ваш первый вопрос.

Чтобы изменить тип коллекции результатов, вы можете использовать collection.breakout (также объясняется в сообщении, которое я связал выше).

scala> val xs = Set(1, 2, 3)
xs: scala.collection.immutable.Set[Int] = Set(1, 2, 3)

scala> val ys: List[Int] = (for(x <- xs) yield 2 * x)(collection.breakOut)
ys: List[Int] = List(2, 4, 6)

Вы можете преобразовать Set в List одним из следующих способов:

scala> List.empty[Int] ++ xs
res0: List[Int] = List(1, 2, 3)

scala> xs.toList
res1: List[Int] = List(1, 2, 3)

Рекомендуемое чтение: Архитектура Scala Коллекции

Ответ 2

Если вы используете map/flatmap/filter вместо понятий, вы можете использовать scala.collection.breakOut для создания другого типа коллекции:

scala> val result:List[Int] = values.map(2*)(scala.collection.breakOut)
result: List[Int] = List(2, 4, 6)

Если вы хотите создать свои собственные классы коллекций (что ближе всего к "репликации урожая", что имеет для меня какой-либо смысл), вы должны взглянуть на этот учебник.

Ответ 3

Попробуйте следующее:

val values = Set(1, 2, 3)
val results = for {v <- values} yield (v * 2).toList