scala implicit class reduce 与函数 currying 的非隐式方法中的方法类型不匹配

scala implicit class method type mismatch in reduce vs non-implicit method with function currying

问题:

关于隐式 class 的一些事情混淆了 reduce()。 在隐式 class 内部时,编译器会抱怨 reduce() 第二个参数。 但是当相同的代码在非隐式方法中时,它编译并工作正常。

关于隐式 classes,我错过了什么?

代码:

object ImpliCurri {
    implicit class MySeq[Int](val l: Seq[Int]) {
        //not compiling
        final def mapSum(f:Int=>Int):Int = {
            l.map(x=>f(x)).reduce(_+_)
       //compile error on reduce: Type mismatch. Expected String, fount Int
        }
    }

    // works fine
    def mySum(l:Seq[Int], f:Int=>Int):Int = {
        l.map(x=>f(x)).reduce(_+_)
        // compiles and works no issues
    }
}

MySeq[Int](val l: Seq[Int]) 替换为 MySeq(val l: Seq[Int])

编译器消息的解释:
MySeq[Int] 部分为 class MySeq 定义了一个名为 Int 的抽象类型参数,它(自动)是 Any 的子 class 和影子实际 scala.Int。然后编译器尝试调用 Any 实例的 + 方法。它看到隐式 class scala.Predef.any2stringadd 的声明,它有一个带有签名 def +(other: String): String 的方法,因此编译器认为 + 的第二个参数应该是 String.

您需要删除类型参数 IntInt 在隐式 class 的情况下实际上不是类型 Int,而是一个自由类型参数,它隐藏了 Int.

的名称

编译器错误的原因是编译器从 lambda _ + _ 推断类型 Any(因为类型参数可以是任何东西),并假设 + 将来自类型 Any 上的 toString。如果您在 class 声明中将 Int 替换为 T,您会发现错误是相同的。

这会起作用:

implicit class MySeq(val l: Seq[Int]) {
    final def mapSum(f: Int => Int): Int = {
        l.map(x => f(x)).reduce(_ + _)
    }
 }

它实际上与隐式没有任何关系。如果它只是一个普通的 class.

,你会得到同样的错误

原因是您声明了一个泛型类型:MySeq[Int] 恰好被称为 Int。所以当你说 f: Int => Int 你认为 "Oh, that's an integer" 而编译器认为 "Oh, that means you could fill in any type there!"。 (将所有 Int 替换为 A,效果相同。)

现在编译器处于绑定状态。什么 + 可以应用于任何一对类型?那么,您可以将任何内容转换为 String,而 + 是在 String 上定义的。因此,当编译器意识到这种方法行不通时,您会收到一条非常具有误导性的错误消息。

只需删除 [Int],您所有的 Int 就会真正表达您认为的意思,隐含的 class 版本也可以正常工作。