1. 模式匹配

Scala中的模式匹配类似于Java中的switch语法,但是更加强大。
模式匹配语法中,采用match关键字声明,每个分支采用case关键字进行声明,当需要匹配时,会从第一个case分支开始,如果匹配成功,那么执行对应的逻辑代码,如果匹配不成功,继续执行下一个分支进行判断。如果所有case都不匹配,那么会执行case _ 分支,类似于Java中default语句。

match的细节和注意事项:

  1)如果所有case都不匹配,那么执行case _ 分支,类似于Java中default语句

  2)如果所有case都不匹配,又没有写case _ 分支,那么会抛出MatchError

  3)每个case中,不用break语句,自动中断case

  4)可以在match中使用其它类型,而不仅仅是字符,可以是表达式

  5)=> 类似于 java swtich 的 :

  6)=> 后面的代码块到下一个case, 是作为一个整体执行,可以使用{} 括起来,也可以不括。

    for (ch <- "+-3!") {
var sign = 0
var digit = 0
ch match {
case '+' => sign = 1
case '-' => sign = -1
case _ if ch.toString.equals("3") => digit = 3
case _ => sign = 2
}
println(ch + " " + sign + " " + digit)
} + 1 0
- -1 0
3 0 3
! 2 0

守卫

如果想要表达匹配某个范围的数据,就需要在模式匹配中增加条件守卫

case _  => digit = 3

case _  => sign = 2 //不会走这一步,只会走一个case _

case _ => digit = 3 //默认,如果把它写在最前边,则下面的所有case就都不会走;
给模式匹配增加变量
//如果在case关键字后跟变量名,那么match前表达式的值会赋给那个变量
val ch = 'Y'
ch match {
case '+' => println("ok+")
case a => println("ok2" + a)
case _ => println ("ok3")
}
--->ok2Y
_在scala中的意思: 导包,隐藏类,初始值,函数返回, 参数占位符,模式匹配其他场合
 val list = List("a", "a", "b", "b" )
// list.groupBy(_) 如果写成这个,编译器无法识别是哪个( f(x): 参数还是x: 参数) 省略的
println(list.groupBy(x => x)) //Map(b -> List(b, b), a -> List(a, a)) val list = List(List(1,2), List(1,2))
println(list.flatMap(x => x)) //List(1, 2, 1, 2) val list = List("zs,ls","ww,zl")
println(list.flatMap(_.split(","))) //List(zs, ls, ww, zl)

匹配类型

匹配对象的任意类型,这样做避免了使用isInstanceOf和asInstanceOf方法

    val a = 3
val obj = if (a == 1) 5 //int...
else if (a == 2) "2" //啥也不是
else if (a == 3) BigInt(3) //
else if (a == 4) Map("aa" -> 1) //对象是一个字符串-数字的Map集合
else if (a == 5) Map(1 -> "aa") //对象是一个字符串-数字的Map集合
else if (a == 6) Array(1, 2, 3) //对象是一个数字数组
else if (a == 7) Array("aa", 1) //啥也不是
else if (a == 8) Array("aa") //对象是一个字符串数组 obj match {
case a: Int => println("int...")
//case _ : BigInt => Int.MaxValue
case b: Map[String, Int] => println("对象是一个字符串-数字的Map集合")
case c : Map[Int, String] => println("对象是一个数字-字符串的Map集合")
case d : Array[String] => println("对象是一个字符串数组")
case e : Array[Int] => println("对象是一个数字数组")
case _ : BigInt => println(Int.MaxValue)// <=等效于=> case f : BigInt => println(Int.MaxValue)
// 这里case _ 表示隐藏变量名,即不使用,而不是表示默认匹配,忽略匹配的变量值。
case _ => println("啥也不是")
}

匹配规则

   for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1))){
val result = arr match {
case Array(0) => "0" //Array(0) 匹配只有一个元素且为0的数组
case Array(x, y) => x + "=" + y //) 匹配数组有两个元素,并将两个元素赋值为x和y
case Array(0, _*) => "以0开头和数组" //Array(0,_*) 匹配数组以0开始
case _ => "什么集合都不是"
}
println("result=" + result)
}
/* result=0
result=1=0
result=以0开头和数组
result=什么集合都不是
result=什么集合都不是*/

匹配对象

    // TODO 匹配对象
object Square {
// unapply可以理解为apply方法的反向操作
// unapply一般使用在模式匹配中
def unapply(z: Double): Option[Double] = Some(math.sqrt(z))
def apply(z: Double): Double = z * z //apply方法用于生成伴生类对象,其实也可以理解对象的工厂
}
// 模式匹配使用:
val number: Double = 36.0
number match {
case Square(n) => println(n) //6.0
case _ => println("nothing matched")
}

匹配for循环

  val map = Map("a"->1, "b"->0, "c"->3)
for ((k, v) <- map){
println(k + "->" + v)
}
for ((k, 0) <- map) {
println(k + " --> " + 0) //b --> 0
}
for ((k, v) <- map if v == 3){
println(k + " --> " + 3) //c --> 3
}

样例类  可直接构建对象且可以做模式匹配

样例类仍然是类; 样例类用case关键字进行声明。 样例类是为模式匹配(对象)而优化的类

构造器中的每一个参数都成为val——除非它被显式地声明为var;

在样例类中一定会有伴生对象,它提供apply方法让你不用new关键字就能构造出相应的对象;  提供unapply方法(与apply是反向的,由对象可推断出类型)让模式匹配可以工作

将自动生成toString、equals、hashCode和copy方法(有点类似模板类,直接给生成,供程序员使用)

除上述外,样例类和其他类完全一样。你可以添加方法和字段,扩展它们

    abstract class Amount
case class Dollar(value: Double) extends Amount //继承抽象类
case class Currency(value: Double, unit: String) extends Amount //样例类不需要{ }里边的主体内容了,case 类名就相当于伴生对象,伴生对象就是负责来构建对象;
case object NoAmount extends Amount //说明: 这里的 Dollar,Currencry, NoAmount 是样例类。
//可以这样理解样例类,就是样例类会默认其它很多的方法,供程序员直接使用
//当我们有一个类型为Amount的对象时,可以用模式匹配来匹配他的类型,并将属性值绑定到变量(即:把样例类对象的属性值提取到某个变量)
for (amt <- Array(Dollar(1000.0), Currency(1000.0, "RMB"), NoAmount)) { //Araay里边有3个对象,它们不是new出来的,伴生对象不需new可直接传值(里边有apply方法,不需声明)
val result = amt match { //进行匹配
case Dollar(v) => "$" + v
case Currency(v, u) => v + " " + u
case NoAmount => ""
}
println(amt + ": " + result)
/* Dollar(1000.0): $1000.0
Currency(1000.0,RMB): 1000.0 RMB
NoAmount: */
}
    case class User(var name: String)  //把参数变成了属性,加上var即是可变的
val user: User = User("kris")
//放不进去,要在name参数前加var
user.name = "alex"
println(user.name) //alex

密封类

把所有的样例类都放一块,加上sealed后,就只能放在一块了,不能放在别的源文件中;

如果想让case类的所有子类都必须在申明该类的相同的源文件中定义,可以将样例类的通用超类声明为sealed,这个超类称之为密封类。
密封就是不能在其他文件中定义子类。

2. 隐式转换

编译器是看编译语法,不会给你执行;

隐式转换即二次编译(自动转换) 不改变之前程序前提下,扩展功能

object ObjectTest1 extends App {
//自动转换
val parent: ParentClass = new ChildClass //子类对象可自动转换为父类
val child: ChildClass = parent.asInstanceOf[ChildClass] //父类对象不能直接转换为子类 ,要先判断下是不是这个类的实例
// byte => short ==> int ==> long
var b : Byte = 19
var s : Short = b
b = s.toByte }
class ParentClass{
}
class ChildClass extends ParentClass{ }

scala允许开发者自己定义类型转换规则,遵循了OCP规则(不对之前的代码做任何改变,隐式转换即可实现)

当scala编译器在编译时发现类型错误,尝试从开发者的位置查找转换规则进行二次编译

object Testimplicit extends App {

  implicit def tranform(d: Double): Int = {
d.toInt
}
val i : Int = 3.4
println("i = " + i)
}

隐式转换规则不仅仅是可以转换类型,还可以扩展功能

object Testimplicit extends App {

  class Person {//extends User

  }
class User{
def login()={
println("user login....")
}
} //隐式转换可以将指定的类型转换为其他的类型,进行功能的扩展
implicit def transform(p:Person): User ={ //想要一个Person,传参; User类型的
new User
}
var p = new Person
p.login //把用户的功能给扩展过来,可以继承(从概念上反了应该User继承Person),这时可用隐式转换
} ==>user login....

scala中允许方法参数进行隐式转换  相同类型的参数做转换;

  def test(implicit name: String = "kris")={  //方法里边这个值是写死的
println(name)
}
//scala中允许方法参数进行隐式转换
implicit val username: String = "alex" //这个值是可以灵活变化的,可以把一个动态变化的值传进去,而不是一个固定值
test //不传参数结果是alex,scala在编译时就会尝试着在作用域内看看有没有一个隐式的变量可以用,如果有就把这个隐式的变量传进来;
test() //kris

隐式转换类是从scala2.10版本后增加的,类声明时必须有一个参数的构造方法;

  通过一个方法把一个类型变成另外一个类型,隐式类是把一个类型转换为当前类型 

    implicit class Person1(user: User11){
def test()={
println("test...")
}
}
class User11{ }
val user = new User11
user.test() //test...

隐式转换在scala编译时进行查找,默认当前作用域范围;  如果当前作用域范围查找不到,会从上级的伴生对象, 包对象查找

object Testimplicit extends App {
val users = new Users()
users.test()
class Users extends MyTrait{ }
} trait MyTrait{
}
object MyTrait{
implicit class Test1(name: Users){
def test()={
println("test...")
}
}
}

Scala模式匹配| 隐式转换的更多相关文章

  1. scala自定义隐式转换

    Scala自定义隐式转换 一.编写隐式转换类 /** * Author Mr. Guo * Create 2019/4/20 - 17:40 */ object StringImprovments { ...

  2. Scala学习——隐式转换

    scala隐式转换 一.需求:为一个类添加一个新的方法 java:动态代理 scala:隐式转换 隐式转换例子: 1.man to superMan package top.ruandb.scala. ...

  3. 深入理解Scala的隐式转换系统

    摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码.   使用方式: 1. ...

  4. 转载:深入理解Scala的隐式转换系统

    摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码.   使用方式: 1. ...

  5. Scala之隐式转换

    概述 简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型. 隐式转换有四种常见的使用场景: 将某一类 ...

  6. Scala之隐式转换implicit详解

    假设我们有一个表示文本的行数的类LineNumber: class LineNumber ( val num : Int ) 我们可以用这个类来表示一本书中每一页的行数: val lineNumOfP ...

  7. Scala学习之路 (八)Scala的隐式转换和隐式参数

    一.概念 Scala 2.10引入了一种叫做隐式类的新特性.隐式类指的是用implicit关键字修饰的类.在对应的作用域内,带有这个关键字的类的主构造函数可用于隐式转换. 隐式转换和隐式参数是Scal ...

  8. 深入理解Scala的隐式转换

    摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码.   使用方式: 1. ...

  9. scala的隐式转换

    摘要: 通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来,这种特性可以极大的减少代码量,忽略那些冗长,过于细节的代码.   使用方式: 1. ...

随机推荐

  1. LOJ#2553 暴力写挂

    题意:给定两棵树T1,T2,求d1[x] + d1[y] - d1[lca1(x, y)] - d2[lca2(x, y)]的最大值. 解:考虑把上面这个毒瘤东西化一下.发现它就是T1中x,y到根的路 ...

  2. python之路day04--列表的增删改查,嵌套、元组的嵌套、range、for循环嵌套

    列表增删改查 增加 append li = ['taibai','zy','nvshen'] li.append('aa') print(li) #['taibai', 'zy', 'nvshen', ...

  3. docker系列(1)- 配置

    参考自:https://www.jianshu.com/p/81bf5efff8e0

  4. SQL Server数据库的备份和还

    转:http://blog.csdn.net/zwj7612356/article/details/8188025 在sql server数据库中,备份和还原都只能在服务器上进行,备份的数据文件在服务 ...

  5. SPFA+SLF+LLL

    关于SLF优化 朴素SPFA使用常规队列(FIFO)更新距离,并没有考虑优化出队顺序(dis值小的优先出队)可以在一开始就把各个点的dis值限值小,从而避免大量的松弛操作,从而提高效率.这就是SLF( ...

  6. Vim使用技巧:特定文件类型关联缩进

    Vim如何打开特定文件类型关联自动缩进呢?答案:将filetype indent on写入你的.vimrc文件中

  7. 前端面试题整理—JavaScript篇(一)

    1.JS的基本数据类型和引用数据类型有哪些,两者区别 基本数据类型->string.number.Boolean.null.undefined.symbol 引用数据类型->array.o ...

  8. UML建工工具

    本篇博文简单介绍一下自己在搜索UML建模工具的过程中收集到的一些信息. 如果想用中文的,可以考虑楚凡科技的Trufun Plato,不过最近好像没有怎么更新了. 很多前辈以前用的是Rational R ...

  9. [再寄小读者之数学篇](2014-06-23 二阶导数估计 [中国科学技术大学2013年高等数学B 考研试题])

    设 $f(x)$ 二阶连续可导, $f(0)=f(1)=0$, $\dps{\max_{0\leq x\leq 1}f(x)=2}$. 证明: $$\bex \min_{0\leq x\leq 1}f ...

  10. java(9)类和对象

    一.理解什么是类和对象 万事万物皆对象 1.1.属性——对象具有的特征(特点) 1.2.方法——对象可执行的操作(能干什么事) 1.3.对象的定义: 是一个客观存在的,看的见或摸得着的实体,由属性和方 ...