【问题标题】:Scala: (_) in the SQLContext.scala of SparkSQLScala: (_) 在 SparkSQL 的 SQLContext.scala 中
【发布时间】:2015-04-15 21:29:21
【问题描述】:

Spark 版本是 1.3.0

源代码来自SQLContext.scala(https://github.com/apache/spark/blob/master/sql/core/src/main/scala/org/apache/spark/sql/SQLContext.scala):

 @transient
  protected[sql] val ddlParser = new DDLParser(sqlParser.apply(_))

  @transient
  protected[sql] val sqlParser = {
    val fallback = new catalyst.SqlParser
    new SparkSQLParser(fallback(_))
  }

  protected[sql] def parseSql(sql: String): LogicalPlan = {
    ddlParser(sql, false).getOrElse(sqlParser(sql))
  }

我无法真正理解上面的代码。

  • sqlParser.apply(_) 是如何工作的?

(_)到底是什么? DDLParser的构造函数需要一个参数parseQuery: String => LogicalPlan,但是sqlParser.apply的返回类型是LogicalPlan

  • 同样,fallback(_) 也是apply 调用,(_) 是如何工作的?

【问题讨论】:

    标签: scala apache-spark


    【解决方案1】:

    本例中的下划线表示部分函数应用,这是将方法类型转换为函数类型的一种方式。所以当你写sqlParser.apply(_)时,就相当于x => sqlParser.apply(x)。由于DDLParser构造函数需要String => LogicalPlan类型的参数,而sqlParser.apply返回LogicalPlan,编译器可以推断出x实际上是String,所以sqlParser.apply(_)是@类型987654332@。

    这里有很多选择。在大多数情况下,以下内容是等效的:

    new DDLParser(x => sqlParser.apply(x))
    new DDLParser(x => sqlParser(x))
    new DDLParser(sqlParser.apply(_))
    new DDLParser(sqlParser.apply _)
    new DDLParser(sqlParser(_))
    new DDLParser(sqlParser _)
    new DDLParser(sqlParser.apply)
    new DDLParser(sqlParser)
    

    您可以阅读更多关于方法类型和函数类型之间的区别here

    将方法类型转换为函数类型的另一种密切相关的方法称为 eta 扩展,它在某些上下文中可以互换使用。阅读 Scala here 中的偏函数应用程序、eta 扩展以及下划线的所有其他用途。

    【讨论】:

    • 让我困惑的是:val ddlParser = new DDLParser(sqlParser.apply(_)),当我定义这样一个ddlParser 时,我没有将任何x(字符串类型)传递给它。它是如何进行初始化的?
    • DDLParser 的构造函数需要String => LogicalPlan 类型的参数。构造函数不需要String,而是一个在String 中并返回LogicalPlan 的函数。而sqlParser.apply(_) 正好返回该类型。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-02-28
    • 2016-12-20
    • 2016-06-24
    • 2015-05-22
    • 1970-01-01
    • 2017-12-28
    • 1970-01-01
    相关资源
    最近更新 更多