Это связано с тем, как синтаксис понимания for
трансформируется компилятором в серию вызовов методов. map
, flatMap
и withFilter
нацелены на перестановки for
понятий. Это очень мощная и общая функция, поскольку она позволяет синтаксису работать с произвольными типами. Есть еще кое-что, например, неявное CanBuildFrom
, но, по сути, сопоставление Map
с Iterable[Tuple[A, B]]
дает Map[A, B]
. Подпись фактически перегружена для Map
, чтобы обеспечить такое поведение
В частности, учитывая исходный код ниже
val thisIsMap = for (x <- dummy; y <- x._2.keys) yield new Tuple2(x._1, y)
println(thisIsMap) // Map(1 -> 4, 6 -> 7) - this is not what I want
Перевод примерно такой
val thisIsMap = dummy.flatMap { x =>
x._2.keys.map { y =>
(x._1, y)
}
}
См. эту скрипту
Чтобы получить желаемый список, мы можем написать
val thisIsMap = (for (x <- dummy; y <- x._2.keys) yield (x._1, y)).toList
Однако, если мы рассмотрим то, что мы узнали о for
пониманиях, мы можем записать это более элегантно как
val thisIsMap = for (x <- dummy.toList; y <- x._2.keys) yield (x._1, y)
В приведенном выше примере мы использовали то самое поведение, которое искажало исходный код, делая вывод, что понимание for
вместо List
приведет к List
.
Однако обратите внимание на разницу между преобразованием исходного кода в List
и преобразованием результирующей карты в List
после понимания.
Если мы вызовем toList
для источника (dummy
), мы получим List((1,2), (1,4), (6,7))
, а если мы вызовем его для результата, мы получим List((1,4), (6,7))
по очевидным причинам, поэтому выбирайте тщательно и обдуманно.
person
Aluan Haddad
schedule
10.07.2019