Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/scala/17.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Scala 何时明确说明函数输入的类型?_Scala_Apache Spark_Language Concepts - Fatal编程技术网

Scala 何时明确说明函数输入的类型?

Scala 何时明确说明函数输入的类型?,scala,apache-spark,language-concepts,Scala,Apache Spark,Language Concepts,我能够计算spark集合每个起始字母的平均字长 val animals23 = sc.parallelize(List(("a","ant"), ("c","crocodile"), ("c","cheetah"), ("c","cat"), ("d","dolphin"), ("d","dog"), ("g","gnu"), ("l","leopard"), ("l","lion"), ("s","spider"), ("t","tiger"), ("w","whale")), 2) 或者

我能够计算spark集合每个起始字母的平均字长

val animals23 = sc.parallelize(List(("a","ant"), ("c","crocodile"), ("c","cheetah"), ("c","cat"), ("d","dolphin"), ("d","dog"), ("g","gnu"), ("l","leopard"), ("l","lion"), ("s","spider"), ("t","tiger"), ("w","whale")), 2)
或者

animals23.
    aggregateByKey((0,0))(
        (x, y) => (x._1 + y.length, x._2 + 1),
        (x, y) => (x._1 + y._1, x._2 + y._2)
    ).
    map(x => (x._1, x._2._1.toDouble / x._2._2.toDouble)).
    collect
或与

animals23.
    combineByKey(
        (x:String) => (x.length,1),
        (x:(Int, Int), y:String) => (x._1 + y.length, x._2 + 1),
        (x:(Int, Int), y:(Int, Int)) => (x._1 + y._1, x._2 + y._2)
    ).
    map(x => (x._1, x._2._1.toDouble / x._2._2.toDouble)).
    collect
每一个都导致

Array((a,3.0), (c,6.333333333333333), (d,5.0), (g,3.0), (l,5.5), (w,5.0), (s,6.0), (t,5.0))
我不明白的是:为什么在第二个示例中我需要显式地声明函数中的类型,而第一个示例中的函数可以不使用这些类型

我是说

(x, y) => (x._1 + y.length, x._2 + 1),
(x, y) => (x._1 + y._1, x._2 + y._2)
vs

这可能更像是一个Scala问题,而不是一个火花问题

为什么我需要在中的函数中显式声明类型 第二个示例,而第一个示例的函数可以不使用吗

因为在第一个示例中,编译器能够根据提供的第一个参数列表推断
seqOp
的类型
aggregateByKey
正在使用:

Scala的工作方式是,编译器能够根据第一个参数推断第二个参数列表的类型。因此在第一个示例中,它知道
seqOp
是一个函数
((Int,Int),String)=>(Int,Int)
,这同样适用于
combOp

相反,
combineByKey
只有一个参数列表:

combineByKey[C](createCombiner: (V) ⇒ C, 
                mergeValue: (C, V) ⇒ C, 
                mergeCombiners: (C, C) ⇒ C): RDD[(K, C)] 
如果不明确说明类型,编译器就不知道要推断什么

帮助编译器的方法是显式指定类型参数:

animals23
  .combineByKey[(Int, Int)](x => (x.length,1), 
                           (x, y) => (x._1 + y.length, x._2 + 1),
                           (x, y) => (x._1 + y._1, x._2 + y._2))
  .map(x => (x._1, x._2._1.toDouble / x._2._2.toDouble))
  .collect

编译器不能从
animals23
计算出
createCombiner
x
是一个字符串,因此它的结果(带有
x.length
)必须是一个Int,并从中推断出其他两个函数的类型吗?curry(从编译器的角度,而不是程序员的角度)与单参数列表有什么不同?我不明白为什么编译器会受到这种限制。@Make42理论上是的,编译器可以从前面提供的函数推断类型
C
,但Scala的局部类型推断不是这样工作的。类型信息在参数列表中流动,而不是在参数列表中流动。你可以在第42页读一点关于这一点的内容,也可以看到一个相当弱的解释。通常的回答是“很复杂”。现在我想你的评论“类型信息在参数列表中流动,而不是在参数列表中流动。”对我来说已经足够好了。
combineByKey[C](createCombiner: (V) ⇒ C, 
                mergeValue: (C, V) ⇒ C, 
                mergeCombiners: (C, C) ⇒ C): RDD[(K, C)] 
animals23
  .combineByKey[(Int, Int)](x => (x.length,1), 
                           (x, y) => (x._1 + y.length, x._2 + 1),
                           (x, y) => (x._1 + y._1, x._2 + y._2))
  .map(x => (x._1, x._2._1.toDouble / x._2._2.toDouble))
  .collect