scala 入门3
样例类:
样例类是一种特殊类,它可以用来快速定义一个用于保存数据的类(类似于Java POJO类),而且它会自动生成apply方法,允许我们快速地创建样例类实例对象。后面,在并发编程和spark、flink这些框架也都会经常使用它。
case class Abc(var a1:String, var a2:Int)
方法:
toString
equals
hashCode
copy
样例对象
case object Abc
1. 样例类可以使用类名(参数1, 参数2)快速创建实例对象
2. 定义样例类成员变量时,可以指定var类型,表示可变。默认是不可变的
3. 样例类自动生成了toString、equals、hashCode、copy方法
4. 样例对象没有主构造器,可以使用样例对象来创建枚举、或者标识一类没有任何数据的消息
简单匹配
val result = name match {
case "1" => s"a"
case "2" => s"b"
case "3" => s"c"
case _ => s"none"
}
守卫
a match {
case a if a >= 0 && a <= 1 => a = 1
case a if a > 1 && a < 2 => a = 2
case _ => a = 3
}
匹配类型
value match {
case x: Int => println("Int " + x)
case y: Double => println("Double " + y)
case z: String => println("String " + z)
case _ => throw new Exception("not match exception")
}
匹配集合
val arr = Array(1, 3, 5)
arr match {
case Array(1, x, y) => println(x + " " + y)
case Array(0) => println("only 0")
case Array(0, _*) => println("0 ...")
case _ => println("something else")
}
匹配列表
val lst = List(3, -1)
lst match {
case 0 :: Nil => println("only 0")
case x :: y :: Nil => println(s"x: $x y: $y")
case 0 :: tail => println("0 ...")
case _ => println("something else")
}
匹配元组
val tup = (1, 3, 7)
tup match {
case (1, x, y) => println(s"1, $x , $y")
case (_, z, 5) => println(z)
case _ => println("else")
}
变量声明中的模式匹配
val arr = Range(0, 10).toArray
// 使用模式匹配,获取第二个、第三个、第四个元素的值
val Array(_, x, y, z, _*) = arr
println(s"x=$x, y=$y, z=$z, ")
获取List中的数据
val list = Range(0, 10).toList
// 匹配列表的第一个、第二个元素的值
val x::y::tail = list
println(s"x=$x, y=$y")
匹配样例类(使用@符号分隔case语句,用来获取用于匹配的整个示例对象)
list(2) match {
case obj @ SubmitTask(id, name) => println(s"id=$id, name=$name");println(s"样例类:$obj")
case HeartBeat(time) => println(s"time=$time")
case CheckTimeOutTask => println("检查超时")
}
Option类型
Some(x):表示实际的值
None:表示没有值
getOrElse方法,当Option对应的实例是None时,可以指定一个默认值,从而避免空指针异常
偏函数:在花括号内没有match的一组case语句是一个偏函数(偏函数是一个参数和一个返回值的函数)
val list = List(1,2,3,4,5,6,7)
val list2 = list.filter{
case x if x % 2 == 0 => true
case _ => false
}
println(list2)
正则表达式
val regEx = """正则表达式""".r
val emailRE = """.+@(.+)\..+""".r
val emailList = List("1@qq.com", "2@gmail.com", "3@163.com", "4.com")
val size = emailRE.findAllMatchIn(emailList(0)).size
println(size)
异常
捕获异常
try {
// 代码
}
catch {
case ex:异常类型1 => // 代码
case ex:异常类型2 => // 代码
}
finally {
// 代码
}
抛出异常
throw new Exception("这是一个异常")
样例类自动实现了apply、unapply方法(可以使用scalap反编译一个样例类的字节码)
class Student {
var name:String = _ // 姓名
var age:Int = _ // 年龄
// 实现一个辅助构造器
def this(name:String, age:Int) = {
this()
this.name = name
this.age = age
}
}
object Student {
def apply(name:String, age:Int): Student = new Student(name, age)
// 实现一个解构器
def unapply(arg: Student): Option[(String, Int)] = Some((arg.name, arg.age))
}
object extractor_DEMO {
def main(args: Array[String]): Unit = {
val zhangsan = Student("张三", 20)
zhangsan match {
case Student(name, age) => println(s"姓名:$name 年龄:$age")
case _ => println("未匹配")
}
}
}
泛型
类和特质、方法都可以支持泛型。
泛型方法
def getMiddle[A](arr:Array[A]) = arr(arr.length / 2)
println(getMiddle[Int](arr1))
泛型类
class Pair[T, S](val first: T, val second: S)
case class Person(var name:String, val age:Int)
val p1 = new Pair[String, Int]("张三", 10)
val p2 = new Pair[String, String]("张三", "1988-02-19")
val p3 = new Pair[Person, Person](Person("张三", 20), Person("李四", 30))
使用`<: 类型名`表示给类型添加一个上界,表示泛型参数必须要从上界继承。
U >: T 表示U必须是类型T的父类或本身
S <: T 表示S必须是类型T的子类或本身
协变、逆变、非变
协变: class Pair[+T],这种情况是协变。类型B是A的子类型,Pair[B]可以认为是Pair[A]的子类型
逆变: class Pair[-T],这种情况是逆变。类型B是A的子类型,Pair[A]反过来可以认为是Pair[B]的子类型
非变: 类型B是A的子类型,Pair[A]和Pair[B]没有任何从属关系
Actor介绍
Actor并发编程模型,是一种基于事件模型的并发机制。Actor并发编程模型是一种不共享数据,依赖消息传递的一种并发编程模式,有效避免资源争夺、死锁等情况。
创建Actor的方式和Java中创建线程很类似。下面是具体的步骤:
1. 定义class或object继承Actor特质
2. 重写act方法
3. 调用Actor的start方法执行Actor
Actor的执行顺序
1. 调用start()方法启动Actor
2. 自动执行act()方法
3. 向Actor发送消息
4. act方法执行完成后,程序会调用exit()方法
! 发送异步消息,没有返回值
!? 发送同步消息,等待返回值
!! 发送异步消息,返回值是Future[Any]
1. 使用!、!?、!!来发送消息
2. actor中使用receive方法来接收消息,需要给receive方法传入一个偏函数
scala
{
case 变量名1:消息类型1 => 业务处理1,
case 变量名2:消息类型2 => 业务处理2,
...
}
3. receive方法只接收一次消息,接收完后结束Actor
在scala中,可以使用loop + react来复用线程。比while + receive更高效
1. 在编写Actor程序时,一般使用样例类来封装消息
2. 在Actor的act方法中,可以使用sender来获取发送方Actor的引用
3. Future表示发送有返回的异步消息的封装,虽然获取到了Future的返回值,但Future中不一定有值,因为可能在将来的某一时刻才会返回消息
4. 使用Future的isSet()可以检查是否已经收到返回消息,使用apply()方法可以获取返回的消息。
5. 使用TimeUnit.SECONDS.sleep来让Actor对应的线程睡眠阻塞
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!