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
.
您需要删除类型参数 Int
。 Int
在隐式 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 版本也可以正常工作。
问题:
关于隐式 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
.
您需要删除类型参数 Int
。 Int
在隐式 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 版本也可以正常工作。