В первых двух случаях у вас возникает ситуация, когда у вас есть Map[K, V]
и Seq[(K, V)]
- потому что Seq[A] <: Iterable[A]
, Scala выберет более конкретный c случай с ++(seq: Iterable[(K, V)]): Map[K V]
.
В третьем случае, однако, вы используете экзистенциальный тип. Это означает, что «существует некоторый тип X и Y, для которого ваш тип равен Map[X, Y]
», тогда как добавляемая вами последовательность имеет вид Seq[(A, B)]
- A
, а B
может иметь тип X
и Y
, но так как мы ничего о них не знаем, мы не можем этого допустить. Вы можете передать пустую карту типа Map[Nothing, Nothing]
или Map[Unit, Unit] = Map(() -> ())
, и она с радостью примет ее.
Что она может сделать в этом случае? Ну, все Map
являются последовательностями пар (что гарантирует, что первый элемент пары является уникальным), и он обеспечивает ++
, который именно это и делает - объединяет ваш Iterable[Z]
с этой последовательностью.
Итак, все сводится к тому, что _
в сигнатуре типа означает экзистенциальный тип. Map[_, _]
является ярлыком для Map[X, Y] forSome { type X; type Y }
. Вы знаете, что есть какой-то тип, который удовлетворяет требованиям, но ни вы, ни компилятор не знают достаточно, чтобы что-то доказать об этом. И поскольку Scala (и большинство типизированных языков) выбирает наиболее конкретное c определение (что означает "более конкретный c", определено в спецификации языков), Map[X, Y] ++ Seq[(X, Y)]
выбирает версию, которая возвращает Map[X, Y]
, и когда он не может доказать, что типы выровнены, он возвращает Iterable
.
Если вы запустите это в аммоните для проверки ваших типов вывода, вы увидите, что тип третьего случая равен Iterable[(Any, Any)]
, поскольку Scala имел найти общий тип для (_, _)
и (K, V)
. REPL лучше отображает типы interred, чем отражение времени выполнения, которое теряет информацию из-за стирания типов.
@ def test1[A, B](map: Map[A, B], a: A, b: B) = {
map ++ Seq(a -> b)
}
defined function test1
@
@ def test2(map: Map[Any, Any], a: Any, b: Any) = {
map ++ Seq(a -> b)
}
defined function test2
@
@ def test3(map: Map[_, _], a: Any, b: Any) = {
map ++ Seq(a -> b)
}
defined function test3
@
@ test1(Map(1 -> "A"), 2, "B")
res15: Map[Int, String] = Map(1 -> "A", 2 -> "B")
@
@ test2(Map(1 -> "A"), 2, "B")
res16: Map[Any, Any] = Map(1 -> "A", 2 -> "B")
@
@ test3(Map(1 -> "A"), 2, "B")
res17: collection.immutable.Iterable[(Any, Any)] = List((1, "A"), (2, "B"))