Я уже некоторое время использую scala, и я подумал, что действительно начинаю понимать все (ну, большинство вещей ...), но я был озадачен рядом определений методов в классе Map. Я знаю, как работают foldLeft и т. Д., Но меня смущает то, что параметры типа используются в функциях Map. Давайте использовать в качестве примера foldLeft:
foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B
Определение для признака самой карты принимает два параметра типа «A» и «B» (например, Map [A, + B]). Из того, что я могу сказать, когда вы определяете параметр типа для метода, используя то же имя, что и один из параметров типа для класса / признака, он переопределяет значение класса / признака. Возьмем это определение Foo в качестве примера:
class Foo[A : Manifest, B : Manifest] {
def isAString() = manifest[A] == manifest[String]
def isAInt() = manifest[A] == manifest[Int]
def isBString() = manifest[B] == manifest[String]
def isBInt() = manifest[B] == manifest[Int]
def nowIsBString[B : Manifest] = manifest[B] == manifest[String]
}
scala> val f = new Foo[String,Int]
f: Foo[String,Int] = Foo@7bacb41
scala> f.isAString
res290: Boolean = true
scala> f.isAInt
res291: Boolean = false
scala> f.isBString
res292: Boolean = false
scala> f.isBInt
res293: Boolean = true
scala> f.nowIsBString[String]
res294: Boolean = true
scala> f.nowIsBString[Int]
res295: Boolean = false
Таким образом, в определении foldLeft «B» происходит из определения метода, а «A» - из определения признака. Например:
val xm = Map("test" -> 1, "test2" -> 2)
scala> val foldFn = (z: Int, kv: (String, Int)) => z + kv._2
foldFn: (Int, (String, Int)) => Int = <function2>
scala> m.foldLeft(0)(foldFn)
res298: Int = 3
Это то же самое, что и 'B' для функции, совпадающей с 'B' для признака, но что если я поменяю тип 'B' для функции на String вместо Int:
scala> val foldFn = (z: String, kv: (String, String)) => z + kv._2
foldFn: (String, (String, String)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
<console>:19: error: type mismatch;
found : (String, (String, String)) => java.lang.String
required: (java.lang.String, (java.lang.String, Int)) => java.lang.String
m.foldLeft("")(foldFn)
Итак, давайте изменим параметр kv на (String, Int):
scala> val foldFn = (z: String, kv: (String, Int)) => z + kv._2
foldFn: (String, (String, Int)) => java.lang.String = <function2>
scala> m.foldLeft("")(foldFn)
res299: java.lang.String = 12
В отличие от моего примера Foo, в этом случае значение «B» карты имеет приоритет над определением функций, но только для параметра kv. То, что я ожидал, это увидеть foldLeft, определенный следующим образом:
foldLeft[C] (z: C)(op: (C, (A, B)) => C): C
Это было бы более понятно для меня, но это не определено таким образом. Так кто-нибудь знает правила, когда параметр методов переопределяет параметр trait / class, а когда нет -