Я работал над Основной доклад Одерского ScalaDays 2011 , где он строит генератор синонимов телефонных номеров в удивительно нескольких строках кода, когда я добрался до этой конкретной строки (присваивая charCode
):
val mnem: Map[Char, String] = // phone digits to mnemonic chars (e.g. '2' -> "ABC")
val charCode: Map[Char, Char] = for ((digit, str) <- mnem; letter <- str)
yield (letter -> digit) // gives ('A', '2'), ('B', '2') etc
Почему charCode
типа Map
?
Когда я получаю кортежи в других примерах, я просто получаю последовательность кортежей, а не карту. Например:
scala> for (i <- 1 to 3) yield (i -> (i+1))
res16: scala.collection.immutable.IndexedSeq[(Int, Int)] = Vector((1,2), (2,3), (3,4))
Можно легко преобразовать это в карту с помощью toMap()
, вот так ...
scala> (for (i <- 1 to 3) yield (i -> (i+1))).toMap
res17: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3, 3 -> 4)
... но как-то пример Одерского избегает этого.
Какую магию Скалы, если таковая имеется, я пропускаю здесь?
Приложение 1: Неявное преобразование? Я хотел бы добавить некоторые детали, относящиеся к комментарию Оксбоу Лейка (примечание: мой комментарий может быть частично ошибочным, возможно, немного неправильно понял, возможно, что он получал в).
Я подозревал, что какое-то неявное преобразование происходило, потому что требовалась карта. Поэтому я попробовал итератор Одерского в интерпретаторе, без намеков на то, что он должен производить:
scala> val mnem = Map('2' -> "ABC", '3' -> "DEF", '4' -> "GHI") // leaving as a map, still
scala> for ((digit, str) <- mnem; letter <- str) yield (letter, digit)
res18: scala.collection.immutable.Map[Char,Char] = Map(E -> 3, F -> 3, A -> 2, I -> 4, G -> 4, B -> 2, C -> 2, H -> 4, D -> 3)
(Обратите внимание, что я оставляю mnem
как карту здесь.)
Аналогично, сообщение компилятору, что я хотел карту, не изменило мой собственный результат:
scala> val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1))
<console>:7: error: type mismatch;
found : scala.collection.immutable.IndexedSeq[(Int, Int)]
required: Map[Int,Int]
val x: Map[Int,Int] = for (i <- 1 to 3) yield (i -> (i+1))
С другой стороны, следуя намекам Иццуна (и это похоже на то, что говорил и ОЛ), следующая (тупая) модификация создает карту:
scala> for ((i,j) <- Map(1 -> 2, 2 -> 2)) yield (i -> (i+1))
res20: scala.collection.immutable.Map[Int,Int] = Map(1 -> 2, 2 -> 3)
Так что, если повторное значение берется из карты, каким-то образом создается карта?
Я ожидаю, что ответ должен быть понят (а) преобразованием цикла "for" в его длинные эквиваленты (вызов / вызовы map
) и (б) пониманием того, какие последствия магически вызываются.
Приложение 2: Тип унифицированного возврата : (huynhjl :) Кажется, это так. Мой первый пример конвертируется в
(1 to 3).map(i => (i, i+1)) // IndexedSeq[(Int, Int)]
Тогда как второе становится чем-то похожим на это:
Map(1 -> 2, 2 -> 2).map(i => (i._1, i._1+1)) // Map[Int,Int]
Тип "Map.map", тогда
def map [B, That] (f: ((A, B)) ⇒ B)(implicit bf: CanBuildFrom[Map[A, B], B, That]): That
Ах, банально. ; -)
Приложение 3: Ну, ладно, все было слишком просто. Майлз Сабин обеспечивает / более правильное описание ниже. Еще более тривиально. ;-)