第4课:Scala模式匹配、类型系统彻底精通与Spark源码阅读

更新时间:2023-06-01 17:37:01 阅读量: 实用文档 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Scala模式匹配Scala类型系统Spark源码阅读

(文档来源:Spark IMF)

获取更多大数据Spark相关资料,请关注公众微信号:DT_Spark

Scala模式匹配、类型系统彻底精通与Spark源码阅读

一: 守卫

var ch = ‘+’

ch match {

case '+' => sign = 1

case '-' => sign = -1

case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)

case _ => sign = 0

}

二:模式中的变量

如果在case关键字后跟着一个变量名,那么匹配的表达式会被赋值给那个变量。case _是这个特性的一个特殊情况,变量名是_。

"Hello, world" foreach { c => println (

c match {

case ' ' => "space"

case ch => "Char: " + c

}

)}

三:类型模式

相比使用isInstanceOf来判断类型,使用模式匹配更好

obj match {

case x: Int => x

case s: String => Integer.parseInt(s)

case _: BigInt => Int.MaxValue

case _ => 0

}

捕获异常:

val file = new File(fileName)

try {

Scala模式匹配Scala类型系统Spark源码阅读

Source.fromFile(file).getLines()

}catch{

case e1: FileNotFoundException => println("FileNotFoundException")

case e2: RuntimeException => println("RuntimeException")

case e3: Exception => println("Exception")

}

因为匹配是发生在运行期的,而且JVM中泛型的类型信息会被擦掉,因此不能使用类型来匹配特定的Map类型

四:匹配数组、列表和元组

1)数组

val arr = Array(0,3,4,5,6,7)

arr match {

case Array(0) => "0"

case Array(x, y) => x + " " + y

case Array(0, x @_*) => println(x)

case _ => "something else"

}

2) 列表

val arr = List(0,4,5,6,7,)

arr match {

case List(0) => "0"

case List(x, y) => x + " " + y

case List(0, x @_*) => println(x)

case _ => "something else"

}

或者

arr match {

case 0 :: Nil => "0"

case x :: y :: Nil => x + " " + y

case 0 :: tail => "0 ..."

case _ => "something else"

}

五:提取器

模式匹配来对数组、列表和元组进行了匹配,在这个过程的背后的是提取器(extractor)机制。使用unapply来提取固定数量的对象,使用unapplySeq来提取一个序列。在前面的代码 case Array(0, x) => ...中, Array(0, x)部分实际上是使用了伴生对象中的提取器,实际调用形式是: Array.unapplySeq(arr)。根据Doc,提取器方法接受一个Array参数,返回一个Option。

1)正则表达式是另一个适用提取器的场景。正则有分组时,可以用提取器来匹配分组

val pattern = "([0-9]+) ([a-z]+)".r

"99 bottles" match {case pattern(num, item) => (num, item)}

Scala模式匹配Scala类型系统Spark源码阅读

2)自定义提取器;下面的例子显示电子邮件地址的提取器对象:

object Test {

def main(args: Array[String]) {

println ("Apply method : " + apply("Zara", ""));

println ("Unapply method : " + unapply("Zara@"));

println ("Unapply method : " + unapply("Zara Ali"));

}

// The injection method (optional)

def apply(user: String, domain: String) = {

user +"@"+ domain

}

// The extraction method (mandatory)

def unapply(str: String): Option[(String, String)] = {

val parts = str split "@"

if (parts.length == 2){

Some(parts(0), parts(1))

}else{

None

}

}

}

六:变量声明中的模式

val (x, y) = (1, 2)

val (q, r) = BigInt(10) /% 3 // 返回商和余数的对偶

val Array(first, second, _*) = arr // 将第一和第二个分别给first和second

七:for表达式中的模式

import scala.collection.JavaConversions.propertiesAsScalaMap

for ((k, v) <- System.getProperties()) // 这里使用了模式

println(k + " -> " + v)

for ((k, "") <- System.getProperties()) // 失败的匹配会被忽略,所以只打印出值为空的键

println(k)

八:样例类

abstract class Amount

// 继承了普通类的两个样例类

case class Dollar(value: Double) extends Amount

case class Currency(value: Double, unit: String) extends Amount

// 样例对象

case object Nothing extends Amount

amt match {

case Dollar(v) => "$" + v

Scala模式匹配Scala类型系统Spark源码阅读

case Currency(_, u) => "Oh noes, I got " + u

case Nothing => "" // 样例对象没有()

}

在声明样例类时,下面的过程自动发生了:

构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;

在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;

提供unapply方法使模式匹配可以工作;

生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。

除了上述之外,样例类和其他类型完全一样,方法字段等。

九:匹配嵌套结构

abstarct class Item

case class Article(description: String, price: Double) extends Item

case class Bundle(description: String, price: Double, items: Item*) extends Item

Bundle("Father's day special", 20.0,

Article("Scala for the Impatient", 39.95),

Bundle("Anchor Distillery Sampler", 10.0,

Article("Old Potrero Straight Rye Whisky", 79.95),

Article("Junipero Gin", 32.95)

)

)

模式可以匹配到特定的嵌套:

case Bundle(_, _, Article(descr, _), _*) => descr

十:密封类

当使用样例类来做模式匹配时,如果要让编译器确保已经列出所有可能的选择,可以将样例类的通用超类声明为sealed。 密封类的所有子类都必须在与该密封类相同的文件中定义。如果某个类是密封的,那么在编译期所有的子类是可知的,因而可以检查模式语句的完整性。让所有同一组的样例类都扩展某个密封的类或特质是个好的做法。

sealed abstract class TrafficLightColor

case object Red extends TrafficLightColor

case object Yellow extends TrafficLightColor

case object Green extends TrafficLightColor

color match {

case Red => "stop"

case Yellow => "hurry up"

case Green => "go"

}

十一:Option类型

Option类型用来表示可能存在也可能不存在的值。样例子类Some包装了某个值,而样例对象None表示没有值。Option支持泛型。

Scala模式匹配Scala类型系统Spark源码阅读

val map = Map(3 -> “a”, 4 -> “b”)

map.get(3) match {

case Some(x) => x

case Nome

}

十二:偏函数

被包在花括号内的一组case语句是一个偏函数。

偏函数是一个并非对所有输入值都有定义的函数,是PartialFunction[A, B]类的一个实例,其中A是参数类型,B是返回类型。该类有两个方法:apply方法从匹配的模式计算函数值;isDefinedAt方法在输入至少匹配其中一个模式时返回true。

val f: PartialFunction[Char, Int] = { case '+' => 1; case '-' => -1 }

f('-') // 返回-1

f.isDefinedAt('0') // false

f('0') //抛出MatchError

本文来源:https://www.bwwdw.com/article/yk91.html

Top