当我编译以下代码时,它会失败并引发错误:
MainTest.scala:11:错误:缺少读入方法的参数列表 对象MainTest
object GenericTest {
def createStream[T: ClassTag](endpoint: String, shardId: Int, func: RecordEntry => T): DStream[T] = {
null
}
def createStream[T: ClassTag](endpoint: String,func: RecordEntry => T): DStream[T] = {
null
}
}
object MainTest {
def main(args: Array[String]): Unit = {
val ddd = GenericTest.createStream[String]("6", 1, read)
}
def read(record: RecordEntry): String = {
s"${record.getString(0)},${record.getString(1)}"
}
}
如果我在GenericTest中删除了第二个方法createStream,则MainTest可以成功编译。 或者,如果我按如下方式修改MainTest(调用GenericTest.createStrem(xxx)时删除“ [String]”,则它可以成功编译。)
def main(args: Array[String]): Unit = {
//remove the "[String]"
val ddd = GenericTest.createStream("6", 1, read)
}
或者如果我如下修改MainTest(将红色转换为func添加),则可以成功编译。
def main(args: Array[String]): Unit = {
// add the " _" after read parameter
val ddd = GenericTest.createStream[String]("6", 1, read _)
}
关于此问题的任何想法,为什么会编译失败?正确的方式应该是什么样的?
答案 0 :(得分:1)
编译错误提示
Error:(25, 58) missing argument list for method read in object MainTest
Unapplied methods are only converted to functions when a function type is expected.
You can make this conversion explicit by writing `read _` or `read(_)` instead of `read`.
val ddd = GenericTest.createStream[String]("6", 1, read)
所以请选择其中一个
val ddd = GenericTest.createStream[String]("6", 1, read _)
或
val ddd = GenericTest.createStream[String]("6", 1, read(_))
答案 1 :(得分:1)
该错误是由于尝试将方法作为函数传递而引起的。诸如read
之类的方法与对象相关联,因此不能将其称为裸函数。
表达式read _
被称为read
的{{3}},它基本上将MainTest
对象绑定到read
方法以创建裸函数。 / p>
因此,您已经在问题的最后一小段代码中有了正确的方法。
那么,如果只有_
的一个版本,为什么没有createStream
也能工作?
错误消息显示:
只有在需要函数类型时,才会将未应用的方法转换为函数。
换句话说,如果您在知道某个方法需要函数的情况下传递了一个方法,则编译器将自动进行此转换。
当createStream
有一个单一版本时,编译器可以将提供的值与该方法的参数进行匹配。它知道功能RecordEntry => T
是必需的,因此它可以完成从方法到功能的转换(eta扩展)。
当createStream
有多个重载版本时,编译必须首先确定正在调用哪个版本。它将值的数量和类型与createStream
的每个版本的参数的数量和类型进行比较。在这种情况下,func
不匹配,因为类型错误:它是方法而不是函数。因此,当有重载方法时,必须将方法转换为适当的重载方法匹配所需的类型。