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

时间:2015-01-21 01:05:01

标签: function scala currying implicits

问题:

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

我对隐式类缺少什么?

代码:

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
    }
}

3 个答案:

答案 0 :(得分:5)

您需要摆脱类型参数Int。在隐式类的情况下,Int实际上不是类型Int,而是一个自由类型参数,它隐藏了Int的名称。

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

这将有效:

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

答案 1 :(得分:3)

它与implicits实际上没有任何关系。如果它只是常规class,则会收到相同的错误。

原因是您声明了一个通用类型:MySeq[Int]恰好被称为Int。所以,当你说f: Int => Int时,你会想到"哦,那是一个整数"并且编译器认为,"哦,这意味着你可以在那里填写任何类型!"。 (将所有Int替换为A,它的作用相同。)

现在编译器处于绑定状态。 +你可以适用于任何一种类型?好吧,您可以将任何内容转换为String,并在+上定义String。因此,当编译器意识到这种方法不起作用时,您会得到一个非常误导性的错误消息。

只需删除[Int]即可,Int所有{{1}}实际上意味着您认为的含义,隐式类版本也能正常运行。

答案 2 :(得分:2)

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

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