与scala类型推断混淆和类型不变性

时间:2018-06-17 02:26:52

标签: scala apache-spark

我有以下简单的代码,

public static IEnumerable<T[]> Buffer<T>(this IEnumerable<T> source, int count)
    =>
        source
            .Select((t, i) => new { t, i })
            .GroupBy(x => x.i / count)
            .Select(x => x.Select(y => y.t).ToArray());

RDD [T]是不变的,因此RDD [Person]不是RDD [Product]的子类型,因此在最后一行中存在编译错误。

但我不理解第2行

case class Person(name: String, age: Int) 
val sc: SparkContext = ...
val rdd: RDD[Product] = sc.parallelize(List(Person("a", 1), Person("b", 2))) //line 2
val rdd1 = sc.parallelize(List(Person("a", 1), Person("b", 2)))
val rdd2: RDD[Product] = rdd1 //compiling error

它是RDD [Person]类型,为什么可以将它分配给RDD [Product]?

3 个答案:

答案 0 :(得分:2)

因为Scala中类型推断的一个非常重要的部分是期望类型。这些规则分散在https://www.scala-lang.org/files/archive/spec/2.11/06-expressions.html上,但要解释这个具体案例:

第2行,

  1. sc.parallelize(List(Person("a", 1), Person("b", 2)))输入了预期类型RDD[Product],所以

  2. List(Person("a", 1), Person("b", 2))输入了预期类型List[Product],所以

  3. Person("a", 1)Person("b", 2)输入了预期类型Product,并且此操作成功,因为PersonProduct的子类型。

  4. 编译器插入类型参数

    sc.parallelize[Product](List[Product](Person("a", 1), Person("b", 2)))
    
  5. 请注意,此RDD[Person]永远不会出现在此过程中。即。

    sc.parallelize(List(Person("a", 1), Person("b", 2)))
    
         

    类型为RDD [Person]

    不正确;它可以是这种类型,但在第2行它不是。

答案 1 :(得分:1)

从这里采取:https://www.scala-lang.org/api/2.12.x/scala/Product.html

  

所有产品的基本特征,标准库中包含at   至少scala.Product1通过scala.Product22因此也是他们的   子类scala.Tuple1到scala.Tuple22。此外,所有情况   classes使用综合生成的方法实现Product。

我能够运行你的代码:

import org.apache.log4j.{Level, Logger}
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.SparkSession

object SparkSample {

  object SparkSessionConf {
    val LOCAL_MASTER = "local[*]"
  }

  def initializeSpark(master: String, appName: String): SparkSession = {
    Logger.getLogger("org").setLevel(Level.ERROR)

    SparkSession.builder
      .master(master)
      .appName(appName)
      .getOrCreate()
  }

  case class Person(name: String, age: Int)

  def main(args: Array[String]): Unit = {
    val sparkSession = initializeSpark(SparkSessionConf.LOCAL_MASTER, "SparkTry")

    val rdd: RDD[Product] = sparkSession.sparkContext.parallelize(List(Person("ss", 10), Person("ss", 20)))
    val rdd1: RDD[Product] = sparkSession.sparkContext.parallelize(List(Person("ss", 10), Person("ss", 20)))

  }
}

答案 2 :(得分:0)

Here是关于不变性的详细描述,并解释了为什么你不能将Person类强制转换为Product trait,尽管我们应该能够这样做。