Я работал над анонсом Odersky 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)
... но каким-то образом пример Odersky избегает этого.
Что такое Scala магия, если таковая имеется, я не вижу здесь?
Добавление 1: Неявное преобразование? Я хотел бы добавить некоторые детали, относящиеся к комментарию Oxbow Lake (NB: мой комментарий может быть частично ошибочным, неправильно поняв, возможно, что он был получение).
Я подозревал, что происходит какое-то неявное преобразование, потому что требуется карта. Поэтому я попробовал итератор Odersky в интерпретаторе без каких-либо намеков относительно того, что он должен произвести:
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))
С другой стороны, следуя подсказкам Eastsun (и это, похоже, то, о чем говорит OL), следующая модификация (dorky) производит карту:
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)
Итак, если итерированное значение происходит от карты, как-то создается карта?
Я ожидаю, что ответ должен быть понят: (а) преобразованием цикла "за" в его эквиваленты с длинными буквами (вызов/вызовы 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
Ah, тривиально.; -)
Добавление 3: Ну, ладно, это было слишком просто, все еще. Майлз Сабин обеспечивает более правильную десурацию ниже. Еще более тривиально.;-)