Scala:未指定的值参数证据$ 3

obe*_*tie 3 scala apache-spark

我环顾四周,发现了其他几个例子,但我并不真正理解那些答案究竟发生了什么.

我想了解为什么以下代码无法编译:

val df = readFiles(sqlContext).
    withColumn("timestamp", udf(UDFs.parseDate _)($"timestamp"))
Run Code Online (Sandbox Code Playgroud)

给出错误:

Error:(29, 58) not enough arguments for method udf: (implicit evidence$2: reflect.runtime.universe.TypeTag[java.sql.Date], implicit evidence$3: reflect.runtime.universe.TypeTag[String])org.apache.spark.sql.UserDefinedFunction.
Unspecified value parameter evidence$3.
            withColumn("timestamp", udf(UDFs.parseDate _)($"timestamp")).
                                                         ^
Run Code Online (Sandbox Code Playgroud)

而这段代码确实编译:

val parseDate = udf(UDFs.parseDate _)
val df = readFiles(sqlContext).
    withColumn("timestamp", parseDate($"timestamp"))
Run Code Online (Sandbox Code Playgroud)

显然我找到了"解决方法",但我真的很想了解:

  1. 这个错误究竟意味着什么.我在TypeTags和ClassTags上找到的信息一直很难理解.我不是来自Java背景,这可能没有帮助,但我想我应该能够掌握它...
  2. 如果我没有单独的函数定义就可以实现我想要的

Ald*_*nio 6

错误信息确实有点误导; 原因是该函数udf采用隐式参数列表,但您传递的是实际参数.因为我不知道很多关于火花,并且由于udf签名是有点令人费解,我会尽力解释是怎么回事,有一个简单的例子.

实际上udf是一个给出一些显式参数的函数,一个隐式参数列表给你另一个函数; 让我们来定义给出下面的函数pivotT的,我们有一个隐含Ordering会给作为一个函数,使我们能够一分为二的序列,包含小于元素一个pivot,另一个包含元素是更大:

def buildFn[T](pivot: T)(implicit ev: Ordering[T]): Seq[T] => (Seq[T], Seq[T]) = ???
Run Code Online (Sandbox Code Playgroud)

让我们省略实施,因为它并不重要.现在,如果我执行以下操作:

val elements: Seq[Int] = ???
val (small, big) = buildFn(10)(elements)
Run Code Online (Sandbox Code Playgroud)

我将犯你在代码中显示的同样的错误,即编译器会认为我显式传递elements为隐式参数列表,这将无法编译.我的示例的错误消息将与您拥有的错误消息有所不同,因为在我的情况下,我错误地传递给隐式参数列表的参数数量与预期参数列表匹配,然后错误将是关于不排队的类型.

相反,如果我把它写成:

val elements: Seq[Int] = ???
val fn = buildFn(10)
val (small, big) = fn(elements)
Run Code Online (Sandbox Code Playgroud)

在这种情况下,编译器将正确地将隐式参数传递给函数.我不知道有什么办法可以绕过这个问题,除非你想明确地传递实际的隐含参数,但我觉得它很难看并且并不总是实用的; 作为参考,这就是我的意思:

val elements: Seq[Int] = ???
val (small, big) = buildFn(10)(implicitly[Ordering[Int]])(elements)
Run Code Online (Sandbox Code Playgroud)

  • 在你的例子中,你也可以做`(buildFn(10)_)(elements)`或`buildFn(10).apply(elements)`.对于`udf`应用程序也可以这样做. (2认同)