使用Scala通用参数编译失败

时间:2019-02-21 07:45:34

标签: scala generics

当我编译以下代码时,它会失败并引发错误:

  

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

关于此问题的任何想法,为什么会编译失败?正确的方式应该是什么样的?

2 个答案:

答案 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不匹配,因为类型错误:它是方法而不是函数。因此,当有重载方法时,必须将方法转换为适当的重载方法匹配所需的类型。