我已经使用 scala 一段时间了,我认为我真的开始理解一切(好吧,大多数事情......),但我发现自己对 Map 类中的许多方法定义感到困惑。我知道 FoldLeft 等如何工作,但我感到困惑的是 Map 函数中使用的类型参数。我们以 FoldLeft 为例:
foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B
Map 特征本身的定义采用两个类型参数“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 示例不同,在这种情况下,Map 的“B”值优先于函数定义,但仅限于 kv 参数。我期望看到的 FoldLeft 定义如下:
foldLeft[C] (z: C)(op: (C, (A, B)) => C): C
这对我来说会更清楚,但它不是这样定义的。那么有谁知道方法参数何时覆盖特征/类参数以及何时不会覆盖的规则?