当特征/类类型参数优先于方法类型参数时,有哪些规则

时间:2012-03-31 18:46:27

标签: scala type-parameter

我一直在使用scala一段时间了,我以为我真的开始理解一切(好吧,大多数事情......),但我发现自己对Map类中的一些方法定义感到困惑。我知道foldLeft等是如何工作的,但我很困惑的是Map函数中使用的类型参数。我们以foldLeft为例:

foldLeft [B] (z: B)(op: (B, (A, B)) ⇒ B) : B

Map trait本身的定义采用两个类型参数'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

这对我来说会更清楚,但不是这样定义的。那么有没有人知道method参数何时覆盖trait / class参数的规则以及什么时候不会?

1 个答案:

答案 0 :(得分:1)

Scala在这方面与Java相同,the Java specification的“名称”章节中的以下内容适用:

  

名为 n 的类型的声明 d 会影响任何声明   名为 n 的其他类型,它们在 d 发生的范围内   在 d 的范围内。

因此,方法的类型参数将始终使用相同名称隐藏类或特征类型参数。您的Foo示例演示了这一事实。

您在Map foldLeft的情况下看到的明显反例只是当前版本Scaladoc的an unpleasant artifact,答案中的pointed out也是如此关于你已经链接的问题。 foldLeft特征中没有定义Map,而TraversableOnce中没有B,其中根本没有名为{{1}}的特征类型参数。

一般来说,遮蔽方法中特征或类的类型参数当然是个坏主意。

相关问题