scala语言中case关键字的三种用途,以及在spark中的一种特殊用法

在scala中,case关键字有多种用途

  1. 可以用作模式匹配,例如
    var arr = Array(1,2,3,4,5,6)
    arr.foreach(i => {
        case 1 => println("==1")
        case _ => println("!=1")
    })
  1. 可以使用在类class前面声明为case class

class之前添加case可以自动生成equal、hashcode、toString、copy方法和他的伴生对象,并且为伴生对象生成apply、unapply方法。例如

case class People(name:String)

val ma = People.apply("Jack")
println(ma.name)
  1. 用于创建偏函数

因为case语句从本质上讲就是PartialFunction的子类。所以在Scala中,被“{}”包含的一系列case语句可以被看成是一个函数字面量。例如:

val second:PartialFunction[List[Int],Int] = {
    case List(x::y::_) => y
}

second函数的功能是返回一个List[Int]中的第二个值。case函数体只涵盖了当一个List的长度大于2的情况,而忽略Nil和长度为1的列表。

case 关键字在spark中的应用

先介绍一下偏函数:

在Scala中,所有偏函数的类型皆被定义为PartialFunction[-A, +B]类型,PartialFunction[-A, +B]又派生自Function1。由于它仅仅处理输入参数的部分分支,因而它通过isDefineAt()来判断输入值是否应该由当前偏函数进行处理。

由此可以看出偏函数:

1)是一个将类型A转为类型B的特质。

2)接受A类型的输入参数,返回值为B类型。

3)是一个一元函数,“-”符号作用于类型表示逆变,-A表明输入参数为A类型或A类型的父类,也就是说输入的参数应为A的子集,具有“部分”的含义。

4)函数有可能“偏”离了A定义域(Type)类型,而成为值域B, +表明可以是B或B的子类,具有“全部”的含义。

观察下面一段处理PairRdd的代码:

val zipped = data.rdd.map((s :Row) => s(0)).zip(tfidf)
val originData = zipped.map( line => LabeledPoint(line._1.asInstanceOf[Int], line._2))

因为line._1的类型被自动推断为Any,所以我们需要使用asInstanceOf将其转换为Int的引用类型。

如果使用case关键字可以这样写:

val zipped = data.rdd.map((s :Row) => s(0)).zip(tfidf)
val originData = zipped.map{ case (x1 :Int, x2 :Vector) => LabeledPoint(x1, x2) }

这是由于偏函数的特质3:-A表明输入参数为A类型或A类型的父类,所以这个匿名函数合法。

这样写更符合函数式编程的风格,另外当我们试图传入一个不在偏函数的定义域范围内的参数时,会抛出异常。如果我们想在调用函数前先检查一个参数是否在定义域范围以避免抛出异常,那么可以使用偏函数的isDefinedAt方法。

参考

  1. Scala偏函数

你可能感兴趣的:(bigdata,spark,spark,scala,mapreduce)