模式匹配隐式转换
2021/5/30 10:24:27
本文主要是介绍模式匹配隐式转换,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
文章目录
- 1 .模式匹配基本概念
- 1.1 什么是模式匹配
- 1.2 基本语法
- 2.模式匹配--匹配种类
- 2.1 匹配常量: 数字 字符 字符串
- 2.2 匹配类型: 整形 字符型 集合类型
- 2.3 匹配具体的集合元素
- 2.4 匹配对象
- 2.5 匹配范围
- 3.模式匹配在变量声明中的使用
- 4.隐式转换
- 4.1 什么是隐式转化
- 4.2 什么情况下会进行隐式转化
- 4.3 隐式函数
- 4.4 隐式参数
- 4.5 隐式类
- 4.6隐式解析机制
- 5 泛型
- 5.1 泛型的基本概念
- 5.2 协变和逆变
1 .模式匹配基本概念
1.1 什么是模式匹配
- 类似于Java中switch语法
1.2 基本语法
- 使用match 关键声明,每个分支使用case关键字声明 匹配不成功会执行case _分支
- 每个 case 中,不需要使用 break 语句,自动中断 case
- => 后面的代码块,直到下一个 case 语句之前的代码是作为一个整体执行 ,可以
使用括起来,也可以不括。
object PatternMatching { def main (args: Array[String]): Unit = { var a: Int = 10 var b: Int = 20 var operator: Char = '+' var result = operator match { case '+' => a + b case '-' => a- b case '*' => a * b case '/' => a / b case _ => "matching fail" } println(result) } }
2.模式匹配–匹配种类
2.1 匹配常量: 数字 字符 字符串
2.2 匹配类型: 整形 字符型 集合类型
object PatternType { def main (args: Array[String]): Unit = { println(decribeConst(true)) println(decribeType(List(2))) println(decribeType(List("hello"))) println(decribeType(Array(5))) println(decribeType(Array("hello"))) } /** * 匹配常量 */ def decribeConst (x: Any) = x match { case 1 => "int one" case "hello" => "string hello" case true => "boolean true" case '+' => "char" + ' ' case _ => "" } /** * 匹配类型 */ def decribeType(x:Any) =x match { case i:Int=>"Int" // 泛型擦除 List类型编译器会忽略泛型 case list:List[String]=>"list " case array:Array[Int]=>"Array[Int]" case a=>"something else" } }
2.3 匹配具体的集合元素
- 匹配列表
// 匹配列表 // 方式一 for (list <- List( List(0),List(1, 0), List(0, 0, 0), List(1, 1, 0),List(88), List("hello") )) { val result = list match { case List(0) => "0" case List(x, y) => "List(x, y): " + x + ", " + y case List(0, _*) => "List(0, ...)" case List(a) => "List(a): " + a case _ => "something else" } println(result) } // 方式二 val list1 = List(1, 2, 5, 7, 24) val list = List(24) list match { case first :: second :: rest => println(s"first: $first, second: $second, rest: $rest") case _ => println("something else") } println("===========================")
- 匹配数组
def main (args: Array[String]): Unit = { for (arr <- List( Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(2, 3, 7, 15), Array("hello", 1, 30) )) { val result = arr match { case Array(0) => s"0 => ${arr.mkString(",")}" case Array(1, 0) => s"Array(1, 0)=> ${arr.mkString(",")}" // 匹配两元素数组 case Array(x, y) => s"Array(x,y)=> ${arr.mkString(",")}" // _* 代表任意多个元素 case Array(0, _*) => s"以0开头的数组=> ${arr.mkString(",")}" case Array(x, 1, z) => s"中间为1的三元素数组=> ${arr.mkString(",")}" case _ => s"something else" } println(result) } }
- 匹配元祖
for (tuple <- List( (0, 1), (0, 0), (0, 1, 0), (0, 1, 1), (1, 23, 56), ("hello", true, 0.5) )){ val result = tuple match { case (a, b) => "" + a + ", " + b case (0, _) => "(0, _)" case (a, 1, _) => "(a, 1, _) " + a case (x, y, z) => "(x, y, z) " + x + " " + y + " " + z case _ => "something else" } println(result)
2.4 匹配对象
- 最原始的 自定义unapply 方法
/** * 匹配对象 */ object MathcObject { def main (args: Array[String]): Unit = { val student = new Student("alice", 19) // 针对对象实例的内容进行匹配 val result = student match { case Student("alice", 18) => "Alice, 18" case _ => "Else" } println(result) } // 定义类 class Student (val name: String, val age: Int) // 定义伴生对象 object Student { // apply 根据传入的值 构建一个对象 def apply (name: String, age: Int): Student = new Student(name, age) // unapply 根据传入的对象 ,还原属性值 用做模式匹配 def unapply (student: Student): Option[(String, Int)] = { if (student == null) { None } else { Some((student.name, student.age)) } } } }
-
说明:
- Student (“alice”, 18) 在执行该语句是 实际调用的是Student1伴生对象中的apply方法
- 执行 case Student1(“alice”, 18) 时,默认调用unapply方法 Student1作为unapply方法的参数 unapply方法将user对象的name 和age 提取出来 与Student1(“alice”,18) 中的属性值进行匹配
- case中对象的unapply方法(提取器)返回Some,且所有属性均一致,才算匹配成功,属性不一致,或返回None,则匹配失败。
- 若只提取对象的一个属性,则提取器为unapply(obj:ob):Option[T]
- 若提取对象的多个属性,则提取器为unapply(obj:Obj):Option[(T1,T2,T3…)]
- 若提取对象的可变个属性,则提取器为unapplySeq(obj:Obj):Option[Seq[T]]
-
使用case关键字简化开发
- case关键字 默认实现unapply 方法
object Test05_MatchCaseClass { def main(args: Array[String]): Unit = { val student = Student1("alice", 18) // 针对对象实例的内容进行匹配 val result = student match { case Student1("alice", 18) => "Alice, 18" case _ => "Else" } println(result) } } // 定义样例类 case class Student1(name: String, age: Int)
- 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中
自动提供了一些常用的方法,如 apply 、 unapply 、 toString 、 equals 、 hashCode 和 copy 。 - 样例类是为模式匹配而优化的类,因为其默认提供了 unapply 方法,因此,样例类可以直接使用模式匹配,而无需自己实现 unapply 方法。
- 构造器中的每一个参数都成为 val ,除非它被显式地声明为 var (不建议这样做)
2.5 匹配范围
def main(args: Array[String]): Unit = { def abs(x: Int) = x match { case i: Int if i >= 0 => i case j: Int if j < 0 => j case _ => "type illegal" } println(abs( 5))
3.模式匹配在变量声明中的使用
object MatchVar { def main (args: Array[String]): Unit = { val (x,y)=(1,2) println(s"$x,$y")//1,2 val Array(first, second, _*) = Array(1, 7, 2, 9,4) println(s"first=$first,second=$second")// first=1,second=7 } }
4.隐式转换
4.1 什么是隐式转化
- 当编译器第一次编译失败的时候,会在当前的环境中查找能让代码编译通过的方法,用
于将类型进行转换,实现二次编译 - 作用: 隐式转换可以在 不需改任何代码的情况下,自动进行类型转换,达到扩展某个类功能的目的
- 实例: 你是否曾希望某个类有某个方法,而这类的作者却没有提供?举例来说 如果java.io.File 类能有read方法来读取文件 那该多好, val contents =new File(“REACME”).read 作为java程序员 你唯一的出路就是向设计者请愿,给类增加一个这样的方法。 而再scala中你可以定义一个经过丰富的类型,提供你想要的功能
class RichFile(val from:File){ def read=Source.fromFilr(from.getPath).mkString }
- 然后再提供一个隐式转换来讲原有的类型转为到这个新类型上
implicit def fire2RichFile(from:File)=new RichFile(from)
- 这样一来 你就可以在File对象上调用read方法了 它被隐式地转换成一个RichFile。File==>RichFile==>调用RichFile的 read方法
4.2 什么情况下会进行隐式转化
- 当对象访问一个不存在的成员时
new File(“README”).read //File 中没有read方法 尝试匹配参数为File对象的隐式函数 尝试将Flie对象转为具有read方法的对象
- 当表达式类型与预期的类型不同时
sqrt(Fraction(1,4)) // sqrt预期的是一个Double 将调用fraction2Doubel
- 当对象调用某个方法 而该方法的参数声明与传入的参数不匹配时
3* Fraction(4,5) // 将掉用int2Fraction 因为int的* 方法不接受Fraction作为参数
4.3 隐式函数
- 需求:通过隐式转化为 Int 类型增加方法。
package chapter09plus object Test02_Implicit { def main(args: Array[String]): Unit = { // 正常调用 val new12 = new MyRichInt(12) println(new12.myMax(15)) // 1. 隐式函数 implicit def convert(num: Int): MyRichInt = new MyRichInt(num) // 如果整型没有 myMax的方法 编译器会在当前作用域内找implicit声明的函数 // 尝试将整数转为能调用myMax方法的对象 println(12.myMax(15)) println("============================") // 2. 隐式类: implicit class MyRichInt2(val self: Int) { //自定义比较大小的方法 def myMax2(n: Int): Int = if ( n < self ) self else n def myMin2(n: Int): Int = if ( n < self ) n else self } println(12.myMin2(15)) // 自定义类 class MyRichInt(val self: Int) { // 自定义比较大小的方法 def myMax(n: Int): Int = if ( n < self ) self else n def myMin(n: Int): Int = if ( n < self ) n else self }
4.4 隐式参数
- 作用:统一管理多个相同的默认值
- 说明:普通方法或者函数中的参数可以通过 implicit 关键字声明为隐式参数,调用该方法时,
就可以传入该参数,编译器会在相应的作用域寻找符合条件的隐式值。- 同一个作用域中,相同类型的隐式值只能有一个
- 编译器按照隐式参数的类型去寻找对应类型的 隐式值,与隐式值的名称无关。
- 隐式参数优先于默认参数
- 实例:
// 3. 隐式参数 implicit val str: String = "alice" // implicit val str2: String = "alice2" implicit val num: Int = 18 // 如果不传 在当前作用域内会匹配implicit 定义的同类型的变量, def sayHello()(implicit name: String): Unit = { println("hello, " + name) } def sayHi(implicit name: String = "atguigu"): Unit = {// 优先匹配隐式参数 println("hi, " + name) } sayHello sayHi // 简便写法 def hiAge(): Unit = { println("hi, " + implicitly[Int]) } hiAge() } }
4.5 隐式类
- 使用implicit关键字修饰的类就是隐式类。若一个变量A没有某些方法或者某些变量时,而这个变量A可以调用某些方法或者某些变量时,可以定义一个隐式类,隐式类中定义这些方法或者变量,隐式类中传入A即可。
- 隐式类注意:
- 隐式类必须定义在类,包对象,伴生对象中。
- 隐式类的构造必须只有一个参数,同一个类,包对象,伴生对象中不能出现同类型构造的隐式类。
//在object当中定义隐式类。使用到前面的person3的参数 implicit class Person4(p: Person3) { def ShowName(): Unit = { println(p.name + " is ShowNaame") } } //在mian方法中调用 val p3 = new Person3("preson3_name") p3.ShowName()
4.6隐式解析机制
- 说明
- 首先会在当前代码作用域(类型的作用域是指与该类型相关联的全部伴生模块)下查找隐式实体(隐式方法、隐式类、隐式对象)。(一
般是这种情况) - 如果第一条规则查找隐式实体失败,会继续在隐式参数的类型的作用域里查找。
类型的作用域是指与 该类型相关联的全部伴生对象 以及 该类型所在包的包对象
- 首先会在当前代码作用域(类型的作用域是指与该类型相关联的全部伴生模块)下查找隐式实体(隐式方法、隐式类、隐式对象)。(一
5 泛型
5.1 泛型的基本概念
- 什么是泛型:泛指的类型
5.2 协变和逆变
- 语法
class MyList [+T]{ 协变 } class MyList[-T]{ 逆变 } class MyList [T]{ 不变 }
- 说明
- 协变:Son是 Father的子类 ,则 My List[ Son ] 也作为 MyList[Father] 的子类
- 逆变:Son是 Father的子类 ,则 My List [Son] 作为 MyList[ Father] 的父类
- 不变:Son是 Father的子类 ,则 My List [ Son]与 MyList[Father] 无父子关系
这篇关于模式匹配隐式转换的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-01后台管理开发学习:新手入门指南
- 2024-11-01后台管理系统开发学习:新手入门教程
- 2024-11-01后台开发学习:从入门到实践的简单教程
- 2024-11-01后台综合解决方案学习:从入门到初级实战教程
- 2024-11-01接口模块封装学习入门教程
- 2024-11-01请求动作封装学习:新手入门教程
- 2024-11-01登录鉴权入门:新手必读指南
- 2024-11-01动态面包屑入门:轻松掌握导航设计技巧
- 2024-11-01动态权限入门:新手必读指南
- 2024-11-01动态主题处理入门:新手必读指南