大数据Scala系列之模式匹配和样例类

本文涉及的产品
云原生大数据计算服务 MaxCompute,5000CU*H 100GB 3个月
云原生大数据计算服务MaxCompute,500CU*H 100GB 3个月
简介: 大数据Scala系列之模式匹配和样例类1.样例类在Scala中样例类是一中特殊的类,样例类是不可变的,可以通过值进行比较,可用于模式匹配。定义一个样例类:1.构造器中每一个参数都是val,除非显示地声明为var 2.

大数据Scala系列之模式匹配和样例类
1.样例类
在Scala中样例类是一中特殊的类,样例类是不可变的,
可以通过值进行比较,可用于模式匹配。
定义一个样例类:
1.构造器中每一个参数都是val,除非显示地声明为var
2.伴生对象提供apply ,让你不使用new关键字就能构造出相应的对象
case class Point(x: Int, y: Int)
创建样例类对象:
val point = Point(1, 2)
val anotherPoint = Point(1, 2)
val yetAnotherPoint = Point(2, 2)
//访问对象值
point.x
point.x =1 //不可以
通过值对样例类对象进行比较:
if (point == anotherPoint) {
println(point + " and " + anotherPoint + " are the same.")
} else {
println(point + " and " + anotherPoint + " are different.")
}
// Point(1,2) 和 Point(1,2)一样的.

if (point == yetAnotherPoint) {
println(point + " and " + yetAnotherPoint + " are the same.")
} else {
println(point + " and " + yetAnotherPoint + " are different.")
}
// Point(1,2)和Point(2,2)是不同的.
样例类的拷贝
You can create a (shallow) copy of an instance of a case class simply by using the copy method. You can optionally change the constructor arguments.
case class Message(sender: String, recipient: String, body: String)
val message4 = Message("julien@bretagne.fr", "travis@washington.us", "Me zo o komz gant ma amezeg")
val message5 = message4.copy(sender = message4.recipient, recipient = "claire@bourgogne.fr")
message5.sender // travis@washington.us
message5.recipient // claire@bourgogne.fr
message5.body // "Me zo o komz gant ma amezeg"
在模式匹配中使用样例类:
abstract class Amount
// 继承了普通类的两个样例类
case class Dollar(value: Double) extends Amount
case class Currency(value: Double, unit: String) extends Amount
case object Nothing extends Amount
object CaseClassDemo {

def main(args: Array[String]): Unit = {

val amt = new Dollar(10);
patternMatch(amt)

}
def patternMatch(amt: Amount) {

amt match {
  case Dollar(v) => println("$" + v)
  case Currency(_, u) => println("Oh noes, I got " + u)
  case Nothing => println("nothing") //样例对象没有()
}

}
}
声明样例类 ,以下几件事会自动发生:
1.提供unapply方法,让模式匹配可以工作
2.生成toString equals hashCode copy 方法,除非显示给出这些方法的定义。
2.模式匹配
1.更好的switch
Scala中类似Java的switch代码:
注意:
Scala的模式匹配只会匹配到一个分支,不需要使用break语句,因为它不会掉入到下一个分支。 match是表达式,与if表达式一样,是有值的:
object PatternDemo {

def main(args: Array[String]): Unit = {

var sign = 0
val ch: Char  = 'p'
val valchar = 'p'
var digit = 0

//match 是表达式

ch match {
  case '+' => sign = 1
  case '-' => sign = -1
  //使用|分割多个选项
  case '*' | 'x' => sign = 2
  //可以使用变量
  //如果case关键字后面跟着一个变量名,那么匹配的表达式会被赋值给那个变量。
  case valchar => sign = 3
  //case _ 类似Java中的default
  // 如果没有模式能匹配,会抛出MacthError
  //可以给模式添加守卫
  case _ if Character.isDigit(ch) => digit = Character.digit(ch, 10)
}
println("sign = "+ sign)

}

}
1常量模式(constant patterns) 包含常量变量和常量字面量
scala> val site = "alibaba.com"
scala> site match { case "alibaba.com" => println("ok") }
scala> val ALIBABA="alibaba.com"
//注意这里常量必须以大写字母开头
scala> def foo(s:String) { s match { case ALIBABA => println("ok") } }
常量模式和普通的 if 比较两个对象是否相等(equals) 没有区别,并没有感觉到什么威力
2 变量模式(variable patterns)
确切的说单纯的变量模式没有匹配判断的过程,只是把传入的对象给起了一个新的变量名。
scala> site match { case whateverName => println(whateverName) }
上面把要匹配的 site对象用 whateverName 变量名代替,所以它总会匹配成功。不过这里有个约定,对于变量,要求必须是以小写字母开头,否则会把它对待成一个常量变量,比如上面的whateverName 如果写成WhateverName就会去找这个WhateverName的变量,如果找到则比较相等性,找不到则出错。
变量模式通常不会单独使用,而是在多种模式组合时使用,比如
List(1,2) match{ case List(x,2) => println(x) }
里面的x就是对匹配到的第一个元素用变量x标记。
3 通配符模式(wildcard patterns)
通配符用下划线表示:"_" ,可以理解成一个特殊的变量或占位符。 单纯的通配符模式通常在模式匹配的最后一行出现,case _ => 它可以匹配任何对象,用于处理所有其它匹配不成功的情况。 通配符模式也常和其他模式组合使用:
scala> List(1,2,3) match{ case List(_,_,3) => println("ok") }
上面的 List(_,_,3) 里用了2个通配符表示第一个和第二个元素,这2个元素可以是任意类型 通配符通常用于代表所不关心的部分,它不像变量模式可以后续的逻辑中使用这个变量。
4.样例类匹配
//定义样例类
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification

//基于样例类的模式匹配
def showNotification(notification: Notification): String = {
notification match {

case Email(email, title, _) =>
  s"You got an email from $email with title: $title"
case SMS(number, message) =>
  s"You got an SMS from $number! Message: $message"
case VoiceRecording(name, link) =>
  s"you received a Voice Recording from $name! Click the link to hear it: $link"

}
}
val someSms = SMS("12345", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
println(showNotification(someSms)) //结果:You got an SMS from 12345! Message: Are you there?
println(showNotification(someVoiceRecording)) //结果:you received a Voice Recording from Tom! Click the link to hear it: voicerecording.org/id/123
2.带守卫的模式
增加布尔表达式或者条件表达式使得匹配更具体。
def showImportantNotification(notification: Notification, importantPeopleInfo: Seq[String]): String = {
notification match {
//仅匹配email在importantPeople列表里的内容

case Email(email, _, _) if importantPeopleInfo.contains(email) =>
  "You got an email from special someone!"
case SMS(number, _) if importantPeopleInfo.contains(number) =>
  "You got an SMS from special someone!"
case other =>
  showNotification(other) // nothing special, delegate to our original showNotification function

}
}

val importantPeopleInfo = Seq("867-5309", "jenny@gmail.com")

val someSms = SMS("867-5309", "Are you there?")
val someVoiceRecording = VoiceRecording("Tom", "voicerecording.org/id/123")
val importantEmail = Email("jenny@gmail.com", "Drinks tonight?", "I'm free after 5!")
val importantSms = SMS("867-5309", "I'm here! Where are you?")

println(showImportantNotification(someSms, importantPeopleInfo))
println(showImportantNotification(someVoiceRecording, importantPeopleInfo))
println(showImportantNotification(importantEmail, importantPeopleInfo))
println(showImportantNotification(importantSms, importantPeopleInfo))
5.类型匹配
可以对表达式类型进行匹配:

val arr = Array("hs", 1, 2.0, 'a')
val obj = arr(Random.nextInt(4))
println(obj)
obj match {
  case x: Int => println(x)
  case s: String => println(s.toUpperCase)
  case _: Double => println(Int.MaxValue)
  case _ => 0
}

注意: 当你在匹配类型的时候,必须给出一个变量名,否则你将会拿对象本身来进行匹配:
obj match {
case _: BigInt => Int.MaxValue // 匹配任何类型为BigInt的对象
case BigInt => -1 // 匹配类型为Class的BigInt对象
}
匹配发生在运行期,Java虚拟机中泛型的类型信息是被擦掉的。因此,你不能用类型来匹配特定的Map类型。
case m: Map[String, Int] => ... // error
// 可以匹配一个通用的映射
case m: Map[_, _] => ... // OK

// 但是数组作为特殊情况,它的类型信息是完好的,可以匹配到Array[Int]
case m: Array[Int] => ... // OK
3.匹配数组、列表、元组
数组匹配
val arr1 = Array(1,1)
val res = arr1 match {
case Array(0) => "0"
//匹配包含0的数组
case Array(x, y) => s"$x $y"
// 匹配任何带有两个元素的数组,并将元素绑定到x和y
case Array(0, _*) => "0..."
//匹配任何以0开始的数组
case _ => "something else"
}
列表匹配
val lst = List(1,2)
val res2 = list match {
case 0 :: Nil => "0"
case x :: y :: Nil => x + " " + y
case 0 :: tail => "0 ..."
case _ => "something else"
}
元组匹配
var pair = (1,2)
val res3 = pair match {
case (0, _) => "0 ..."
case (y, 0) => s"$y 0"
case _ => "neither is 0"
}
4.Sealed 类(密封类,备选)
Scala中,Traits 和classes可以被关键字sealed修饰, 修饰,被该关键字修饰后,它所有的子类都必须在同一文件中被定义。
这样做的好处是:当你用样例类来做模式匹配时,你可以让编译器确保你已经列出了所有可能的选择,编译器可以检查模式语句的完整性。
sealed abstract class Furniture
case class Couch() extends Furniture
case class Chair() extends Furniture
//此时无需定义能匹配所有的类型了
def findPlaceToSit(piece: Furniture): String = piece match {
case a: Couch => "Lie on the couch"
case b: Chair => "Sit on the chair"
}

相关实践学习
基于MaxCompute的热门话题分析
本实验围绕社交用户发布的文章做了详尽的分析,通过分析能得到用户群体年龄分布,性别分布,地理位置分布,以及热门话题的热度。
SaaS 模式云数据仓库必修课
本课程由阿里云开发者社区和阿里云大数据团队共同出品,是SaaS模式云原生数据仓库领导者MaxCompute核心课程。本课程由阿里云资深产品和技术专家们从概念到方法,从场景到实践,体系化的将阿里巴巴飞天大数据平台10多年的经过验证的方法与实践深入浅出的讲给开发者们。帮助大数据开发者快速了解并掌握SaaS模式的云原生的数据仓库,助力开发者学习了解先进的技术栈,并能在实际业务中敏捷的进行大数据分析,赋能企业业务。 通过本课程可以了解SaaS模式云原生数据仓库领导者MaxCompute核心功能及典型适用场景,可应用MaxCompute实现数仓搭建,快速进行大数据分析。适合大数据工程师、大数据分析师 大量数据需要处理、存储和管理,需要搭建数据仓库?学它! 没有足够人员和经验来运维大数据平台,不想自建IDC买机器,需要免运维的大数据平台?会SQL就等于会大数据?学它! 想知道大数据用得对不对,想用更少的钱得到持续演进的数仓能力?获得极致弹性的计算资源和更好的性能,以及持续保护数据安全的生产环境?学它! 想要获得灵活的分析能力,快速洞察数据规律特征?想要兼得数据湖的灵活性与数据仓库的成长性?学它! 出品人:阿里云大数据产品及研发团队专家 产品 MaxCompute 官网 https://www.aliyun.com/product/odps 
相关文章
|
1月前
|
分布式计算 资源调度 大数据
大数据-110 Flink 安装部署 下载解压配置 Standalone模式启动 打包依赖(一)
大数据-110 Flink 安装部署 下载解压配置 Standalone模式启动 打包依赖(一)
52 0
|
1月前
|
分布式计算 资源调度 大数据
大数据-110 Flink 安装部署 下载解压配置 Standalone模式启动 打包依赖(二)
大数据-110 Flink 安装部署 下载解压配置 Standalone模式启动 打包依赖(二)
69 0
|
1月前
|
消息中间件 分布式计算 NoSQL
大数据-104 Spark Streaming Kafka Offset Scala实现Redis管理Offset并更新
大数据-104 Spark Streaming Kafka Offset Scala实现Redis管理Offset并更新
40 0
|
1月前
|
消息中间件 存储 分布式计算
大数据-103 Spark Streaming Kafka Offset管理详解 Scala自定义Offset
大数据-103 Spark Streaming Kafka Offset管理详解 Scala自定义Offset
82 0
|
17天前
|
SQL 存储 算法
基于对象 - 事件模式的数据计算问题
基于对象-事件模式的数据计算是商业中最常见的数据分析任务之一。对象如用户、账号、商品等,通过唯一ID记录其相关事件,如操作日志、交易记录等。这种模式下的统计任务包括无序计算(如交易次数、通话时长)和有序计算(如漏斗分析、连续交易检测)。尽管SQL在处理无序计算时表现尚可,但在有序计算中却显得力不从心,主要原因是其对跨行记录运算的支持较弱,且大表JOIN和大结果集GROUP BY的性能较差。相比之下,SPL语言通过强化离散性和有序集合的支持,能够高效地处理这类计算任务,避免了大表JOIN和复杂的GROUP BY操作,从而显著提升了计算效率。
|
1月前
|
Java 大数据 数据库连接
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
29 2
大数据-163 Apache Kylin 全量增量Cube的构建 手动触发合并 JDBC 操作 Scala
|
1月前
|
存储 分布式计算 druid
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
39 1
大数据-152 Apache Druid 集群模式 配置启动【下篇】 超详细!(一)
|
25天前
|
SQL 存储 算法
基于对象 - 事件模式的数据计算问题
基于对象-事件模式的数据计算是商业中最常见的数据分析任务之一。这种模式涉及对象(如用户、账户、商品等)及其相关的事件记录,通过这些事件数据可以进行各种统计分析,如漏斗分析、交易次数统计等。然而,SQL 在处理这类任务时表现不佳,特别是在有序计算方面。SPL 作为一种强化离散性和有序集合的语言,能够高效地处理这类计算,避免了大表 JOIN 和大结果集 GROUP BY 的性能瓶颈。通过按 ID 排序和分步计算,SPL 能够显著提高计算效率,并支持实时数据处理。
|
1月前
|
分布式计算 大数据 分布式数据库
大数据-158 Apache Kylin 安装配置详解 集群模式启动(一)
大数据-158 Apache Kylin 安装配置详解 集群模式启动(一)
42 5
|
1月前
|
资源调度 大数据 分布式数据库
大数据-158 Apache Kylin 安装配置详解 集群模式启动(二)
大数据-158 Apache Kylin 安装配置详解 集群模式启动(二)
40 2