关于隐式类的东西,混淆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
}
}
答案 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
。