reduceLeft
reduceLeft
Seq
以后,def reduceLeft [B >: A] (f: (B, A) ⇒ B): B
List(1,2,3,4) reduceLeft (_ + _)
的签名是
A
我们可以用
等表达式来调用它Int
在此示例中,reduceLeft
为Function2[B >: Int, Int, B]
,因此B
需要+
。无论reduceLeft如何工作(这是无关紧要的),类型推断器如何知道Any
具有{{1}}方法,何时它可以是{{1}}类型?
答案 0 :(得分:4)
我认为spec类的 6.26.4 Local Type Inference 部分解释了正在发生的事情。编译器将寻找最佳类型。当类型参数是逆变时,所选择的类型将是最大的(在本例中为Any),否则(不变或协变)最小(在本例中为Int)。
有几个例子与reduceLeft
无关。
我注意到的是,在查看传递的匿名函数之前,似乎发生了推断:
scala> List(1,2).reduceLeft[Any](_.toString + _)
res26: Any = 12
但如果我不帮助类型推理器:
scala> List(1,2).reduceLeft(_.toString + _)
<console>:8: error: type mismatch;
found : java.lang.String
required: Int
List(1,2).reduceLeft(_.toString + _)
编辑,我错了将匿名函数考虑在内,这有效:
List(1,2).reduceLeft((_:Any).toString + (_:Any).toString)
您可以运行编译器-Ytyper-debug
选项:
List(1,2).reduceLeft(_+_)
它会告诉你,编译器假定匿名函数的预期类型是(Int, Int) => Int
,然后它继续检查_ + _
对它并成功,然后推断B
为Int
。片段:
typed immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B
adapted immutable.this.List.apply[Int](1, 2).reduceLeft: [B >: Int](f: (B, Int) => B)B to ?, undetparams=type B
typing ((x$1, x$2) => x$1.$plus(x$2)): pt = (Int, Int) => Int: undetparams=,
// some time later
typed ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int
adapted ((x$1: Int, x$2: Int) => x$1.+(x$2)): (Int, Int) => Int to (Int, Int) => Int,
typed immutable.this.List.apply[Int](1, 2).reduceLeft[Int](((x$1: Int, x$2: Int) => x$1.+(x$2))): Int
我不知道为什么在没有类型归属的情况下,匿名函数被假定为(Int, Int) => Int
。
答案 1 :(得分:1)
如果B&gt;:X且编译器知道X但无法解析B,则只假设B = X.
这有点实用,因为它只有B的两个选项,只有一个是已知的。因此,如果不知道哪个超类假设B是X.您可以使用以下代码测试编译器决策过程。
class Y {
def bar(y:Y) = this
}
case class X( i: Int ) extends Y {
def foo(x:X)=X(i+x.i)
}
val t = new Y bar X(7)
val t2 = X(8) bar X(7)
val res = List(X(1),X(2),X(3)) reduceLeft { _ foo _ }
val res2 = List(X(1),X(2),X(3)) reduceLeft { _ bar _ } // will not compile