Scala 知识点总结大全

一、变量、数据类型、运算符

1.1语法声明

变量的类型在变量名之后等号之前声明。

var | val 变量名 :变量类型 = 变量值

变量的类型如果能够通过变量值推断出来,那么可以省略类型声明

1.2 变量初始化

Scala语法中,必须显示进行初始化操作。

1.3 可变变量& 不可变变量

值可以改变的变量,称之为可变变量,但是变量类型无法发生改变, Scala中可变变量使用关键字var进行声明

​ 值一旦初始化后无法改变的变量,称之为不可变变量。Scala中不可变变量使用关键字val进行声明, 类似于Java语言中的final关键字

1.4 字符串

在 Scala 中,字符串的类型实际上就是 Java中的 String类,它本身是没有 String 类的。

​ String 是一个不可变的字符串对象,所以该对象不可被修改

  • 字符串连接

直接使用 “+” 号

// 字符串连接
println("Hello " + name)
  • 传值字符串
 // 传值字符串(格式化字符串)
printf("name=%s\n", name)
  • 插值字符串
 // 插值字符串
 // 将变量值插入到字符串
println(s"name=$name")
println(s”name=${name.subString(0,1)}”)
  • 多行字符串

使用三个引号

  // 多行格式化字符串
        // 在封装JSON或SQL时比较常用
        // | 默认顶格符
        println(
                    s"""
                      | Hello
                      | ${name}
        """.stripMargin)

 

1.5 数据类型

​ Scala是完全面向对象的语言,所以不存在基本数据类型的概念,有的只是任意值对象类型(AnyVal)和任意引用对象类型(AnyRef)

1.6 运算符(==,eq,equal)

==相当于java中的equal,并且会判断是否为空,不会造成空指针

equal也是相当于java中的equal,不会判空,会空指针

eq相当于java中的==,比较的是地址

Scala中没有++ 和 –

1.7 运算符本质

在Scala中其实是没有运算符的,所有运算符都是方法。

scala是完全面向对象的语言,所以数字其实也是对象
当调用对象的方法时,点.可以省略
如果函数参数只有一个,或者没有参数,()可以省略

二、循环控制

2.1 for循环

  • 基本语法:

for ( 循环变量 <- 数据集 ) {

​ 循环体

}

这里的数据集可以是任意类型的数据集合

eg:

object ScalaLoop {
    def main(args: Array[String]): Unit = {
        for ( i <- Range(1,5) ) { // 范围集合 [1,5)
            println("i = " + i )
        }
        for ( i <- 1 to 5 ) { // [1,5]
            println("i = " + i )
        }
        for ( i <- 1 until 5 ) { // 不包含5
            println("i = " + i )
        }
    }
}

 

  • 循环守卫

循环时可以增加条件来决定是否继续循环体的执行,这里的判断条件我们称之为循环守卫

for ( i <- Range(1,5) if i != 3  ) {
            println("i = " + i )
        }

 

  • 循环步长

scala的集合也可以设定循环的增长幅度,也就是所谓的步长step

eg:

for ( i <- Range(1,5,2) ) {
            println("i = " + i )
        }
for ( i <- 1 to 5 by 2 ) {
            println("i = " + i )
        }

2.2 while循环

  • 语法

while( 循环条件表达式 ) {

​ 循环体

}

  • 循环中断

​ scala是完全面向对象的语言,所以无法使用break,continue关键字这样的方式来中断,或继续循环逻辑,而是采用了函数式编程的方式代替了循环语法中的break和continue
Breaks.break是依靠抛出异常来中断程序。

scala.util.control.Breaks.breakable {
            for ( i <- 1 to 5 ) {
                if ( i == 3 ) {
                    scala.util.control.Breaks.break
                }
                println(i)
            }
        }


三、函数式编程

3.1 基础函数编程

3.1.1 基本语法

[修饰符] def 函数名 ( 参数列表 ) [:返回值类型] = {

​ 函数体

}

3.1.2 函数&方法

scala 中存在方法与函数两个不同的概念,二者在语义上的区别很小。scala 方法是类的一部分,而函数是一个对象,可以赋值给一个变量。换句话来说在类中定义的函数即是方法。scala 中的方法跟 Java 的类似,方法是组成类的一部分。scala 中的函数则是一个完整的对象。

3.1.3 函数参数

  • 可变参数

用 * 来表示,可变参数不能放置在参数列表的前面,一般放置在参数列表的最后

def fun7(names:String*): Unit = {
            println(names)
        }

 

  • 参数默认值:函数的参数的类型默认为val的

使用 = 进行参数的默认赋值

def fun8( name:String, password:String = "000000" ): Unit = {
            println( name + "," + password )
        }

3.1.4 函数的至简原则

  • 省略return关键字,
def fun1(): String = {
            return "zhangsan"  //不省略
        }
def fun11(): String = {
            "zhangsan"    //省略return
        }

 

  • 省略花括号。只有一行逻辑
def fun2(): String = "hello world"
  • 省略返回值类型

有return关键字,必须不能省略返回值类型,返回值类型编译器可以进行自动类型推断

def fun3() = "hello scala"
  • 省略参数列表(无参函数)

定义时没有小括号,调用时也不能有小括号,无参的

def fun4:String = "zhangsan"
  • 省略等号

​ 只要省略了等号,那么return是没有意义的,就意味着就是不需要返回值,如果函数体中有明确的return语句,那么返回值类型不能省略

​ 如果函数体返回值类型声明为Unit, 但是又想省略,那么此时就必须连同等号一起省略,但是即使方法体只有一行,这时也不能省略大括号,省略等号的一般返回值是Unit的

def fun5() {  // 方法返回值类型为Unit
            return "zhangsan"
        }
  • 省略名称和关键字,匿名函数

语法: () => { 函数体 }

() => {
            println("zhangsan")
        }

3.2 高阶函数编程

所谓的高阶函数,其实就是将函数当成一个类型来使用,而不是当成特定的语法结构

函数类型表示方法 :(参数1类型,参数2类型。。。) => 返回值类型 eg: (Int, Int) => Int

3.2.1 函数作为值

函数可以作为值赋值给变量。

def fun1(): String = {
            "zhangsan"
        }
val a = fun1  //a  为string类型,fun1 为方法的调用
val b = fun1 _  // b为函数fun1 
val c : () => String = fun1   //c 为函数fun1

3.2.2 函数作为参数

函数可以作为另一个函数的参数。

def fun2( i:Int ): Int = {
            i * 2
        }
def fun22( f : Int => Int ): Int = {  //参数为 Int => Int 的函数
            f(10)
        }
println(fun22(fun2))  //将函数 fun2 作为参数 ,fun22 进行了类型推断,所以fun2 不用加下划线 _ 

//也可以直接使用匿名函数
println(fun22(_ * 2))

3.2.3 函数作为返回值

函数可以作为另一个函数的返回值

def fun3( i:Int ): Int = {
            i * 2
        }
def fun33( ) = {         // 函数的返回值类型为 Int => Int
            fun3 _
        }
println(fun33()(10))  //fun33() 为函数类型,所以可以接着调用

3.2.4 闭包

函数在使用外部变量时,如果外部变量失效时,会将这个变量包含到当前的函数内部,形成闭合的使用效果。改变变量的生命周期,将这种操作称之为closure (闭包)

​ 匿名函数肯定为闭包,将函数赋值给变量使用也是闭包,嵌套函数的使用都为闭包

​ 2.12版本闭包通过重新声明来实现

​ 2.11以前的闭包被编译为匿名函数类,若使用外部变量,会将外部变量作为类的属性

没有使用外部变量还能称之为闭包吗?

在早期版本
2.11,即使没有使用外部变量,也会有闭包的效果,只是没有包含外部的变量
2.12版本中,没有使用外部变量的话,就没有闭包。

3.2.5 函数的柯里化

参数转换,可以将一个参数列表分为多个参数列表

def fun6(i:Int)(j:Int) = {
            i * j
        }

3.2.6 控制抽象

代码作为参数

参数列表中如果有多行逻辑,可以采用大括号代替

scala支持将代码逻辑作为参数传递给函数使用

如果函数参数想要传递代码逻辑,那么类型声明的方式应该为:

参数名: =返回值类型(Unit)

因为参数类型中没有声明小括号,所以调用时,也不能加小括号

def fun7(op: => Unit) = {  //参数类型 : 抽象控制
            op
        }
fun7{                      //方法调用,将代码作为参数,用大括号
            println("xx")
        }

3.2.7惰性函数

当函数返回值被声明为lazy时,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

def fun9(): String = {
            println("function...")
            "zhangsan"
        }
lazy val a = fun9()
println(a)

四、面向对象编程

4.1 面向对象编程基础

4.1.1 包

Scala中的基本的package的语法和Java完全一致。

package 包名

  • 扩展语法

①Scala中的包和类的物理路径没有关系

②package关键字可以嵌套声明使用

③子包可以直接访问父包中的内容,而无需import

④Scala中package也可以看作对象,并声明属性和函数。可以将一个包中共通性的方法或属性在包对象中声明。那么这个包中的所有的类都可以直接访问这个包对象。

4.1.2 导入

Scala中基本的import导入语法和Java完全一致。

import 类名

  • 扩展语法

①Scala中使用下划线代替java中的 * 。eg: import java.util._

②scala中默认导入的类: java. lang包中所有的类、scala包中的类、Predef (类似 java中静态导入)

③Scala中的import语法可以在任意位置使用

④Scala中可以导包,而不是导类

⑤Scala中可以在同一行中导入多个类,简化代码

⑥Scala中可以屏蔽某个包中的类。eg:

import java.sql.{ Date=>_, Array=>_}   //屏蔽sql中的Date、Array

⑦Scala中可以给类起别名,简化使用。eg: import java.util.{ArrayList=>AList}

4.1.3 类

Scala中有伴生类和伴生对象之分。

​ class修饰的类就是普通的伴生类,在使用时需要new对象。而Object用于修饰伴随着这个类所产生的一个单例对象,用于模仿java中的静态语法。object中的方法和属性都可以通过类名直接访问,类似于静态语法。

4.1.4 属性

类的属性就是类变量。在声明的时候,必须进行初始化。也可以使用下划线进行属性的初始化,但是必须明确属性的类型,使用下划线进行初始化的属性一般声明为val的,后面可能要对这个属性进行更改。

​ Scala中的属性其实在编译后也会生成方法。

eg:

val name = "SQLBoy"

//编译后的结果
final String name = "SQLBoy";
public String name() {
         return this.name;
}
public void name_$eq(final String x$1) {
         this.name = x$1;
}

Scala为了迎合Java中的get和set方法,在Scala要想使用get和set方法,需要添加特殊的注解@BeanProperties,添加注解的不能设置为private的

4.1.5 访问权限

private : 私有访问权限:同类

private[包名]: 包访问权限 --> 包可以向上使用:同类,同包, 包名只能跟本包有关系

protected : 受保护权限 : 同类,子类

(default) : 公共访问权限

4.1.6 方法

方法其实就是函数。

​ 但是伴生类中的私有的方法和属性,在其伴生对象中也可以使用。所以当类中的构造器私有化的时候,可以在伴生对象中创建apply方法,通过伴生对象来创建类的对象,在调用时,scala会自动识别apply方法,所以apply方法名可以省略。

​ 伴生对象只能初始化一次,所以通过伴生对象来创建对象是线程安全的。

​ apply主要用来构建对象,不一定是当前类的对象。apply可以重载。

eg:

object ScalaMethod{
    def main(args: Array[String]): Unit = {
        val user = new User  //通过new来创建User 的对象
        user.login("zhangsan", "000000")

        val user2 = User.apply()  //通过伴生类创建对象,
        val user3 = User() // 必须加上小括号,若不加小括号,则user3就是User伴生对象
    }
}
class User {
    def login( name:String, password:String ): Boolean = {
        false
    }
}

object User{  //User 的伴生对象,静态,可以通过类名直接访问,只会初始化一次
   def apply():User={   //不能省略小括号
           new User()
   }
}
  • 小知识点:

重写和重载

方法重载
多个方法名称相同,但是参数列表(参数个数,参数类型,参数顺序)不相同
参数为数值类型,在进行方法重载时,若参数类型符合,则直接调用对应的方法,若无对应的参数类型,则会提高精度。

eg:

Byte a = 1
fun(a)  //由于没有Byte的类型,故进行精度提升,调用参数类型为Int的方法。
def fun(n:Int)={}
def fun(n:Long)={}

引用类型,在重载的方法如果找不到对应的类型。会从类树往上查找

  • 方法重写
  1. 方法的重写一定要存在父子类。
  2. 子类重写父类的方法。子类重写父类相同方法的逻辑
  3. 方法名一致,参数列表保持一致
  4. 既然父类和子类有相同的方法,形成了方法的重写。
  5. 那么在调用时,无法确定到底执行哪一个方法, 那么需要遵循动态绑定机制
  6. 动态绑定机制:程序执行过程,如果调用了对象的“成员”“方法”时,
  7. 会将方法和对象的实际内存进行绑定,然后调用。
  8. 动态绑定机制和属性无关。

4.1.7构造方法

Scala中类其实也是一个函数,类名其实就是函数名,类名后面可以增加括号,表示函数参数列表。这个类名所代表的函数其实就是主构造方法,构造方法执行时,会完成类的主体内容的初始化。

  • ​ scala中提供了2种不同类型的构造方法。

​ ①主构造方法:在类名后的构造方法, 可以完成类的初始化

​ ②辅助构造方法:为了完成类初始化的辅助功能而提供的构造方法。声明方式为: def this0

在使用辅助构造方法时,必须直接或间接地调用主构造方法。

​ Scala中一般构造方法的参数用于属性的初始化,所以为了减少数据的冗余,可以使用关键字var, val将构造参数当成类的属性来用。

/eg:

class User() { // 主构造函数 ,形参中可以添加var、val将形参作为类的属性直接使用
    var username : String = _ 
    def this( name:String ) { // 辅助构造函数,使用this关键字声明
        this() // 辅助构造函数应该直接或间接调用主构造函数
        username = name
    }
    def this( name:String, password:String ) {
        this(name) // 构造器调用其他另外的构造器,要求被调用构造器必须提前声明
    }
}

4.2 面向对象进阶

4.2.1 继承

跟Java一样,使用extends关键字表示类的继承关系。

4.2.2 抽象

​ 抽象方法:不完整的方法,可以不使用abstract关键字

​ 若类中含有抽象方法/抽象属性,则此类必须为抽象类,用abstract关键字进行声明。

​ 抽象类中可以有完整的方法,若子类重写父类的完整方法,必须要用override关键字进行修饰。子类实现父类的抽象方法,可以使用或者不用override关键字。

​ 抽象属性:没有初始化的属性。

​ 子类重写父类的完整属性必须是val的,不能重写var的属性,实现抽象属性则没有要求。重写抽象属性,相当于普通属性的声明,这个属性可以是val和var的,可以使用或者不用override关键字。但是重写普通属性,只能是val的,必须要用override关键字进行修饰。

4.2.3 特质

scala中没有接口。但是增加了特质(trait)。scala可以将多个类中相同的特征,从类中剥离出来,形成特殊的语法"特质"。特质中可以声明抽象方法,也可以声明普通方法。特质的使用需要混入到类中。特质的一个重要的功能:可以进行功能的扩展。

​ 特质也可以看做抽象类,继承其他的类,并用with混入其他的特质。特质又可以使用extends,又可以使用with。

​ java中所有的接口在scala中当成特质使用。

  • 基本语法
trait 特质名称{   //特质的声明
    方法
}
class 类名 extends 父类(特质1) with 特质2 with特质3   //类中混入多个特质
new 类 with 特质1 with 特质2  //动态混入特质

如果类混入多个特质,那么特质的初始化顺序为从左到右
类混入多个特质的时候,功能的执行顺序从右向左

特质中的super其实有特殊的含义,表示的不是父特质,而是上级特质。

eg:注意理解super的含义。

object ScalaTrait {
    def main(args: Array[String]): Unit = {
        val mysql: MySQL = new MySQL
        mysql.operData()  //功能执行,从右到左
    }
}

trait Operate{
    def operData():Unit={
        println("操作数据。。")
    }
}
trait DB extends Operate{
    override def operData(): Unit = {
        print("向数据库中。。")
        super.operData()
    }
}
trait Log extends Operate{
    override def operData(): Unit = {
        print(“hello”)
        super.operData()
    }
}
class MySQL extends DB with Log {

}
最终结果:hello向数据库中。。操作数据。。


五、集合

Scala的集合有三大类:序列Seq、集Set、映射Map。对于几乎所有的集合类,Scala都同时提供了可变和不可变的版本。

5.1 数组

5.1.1 不可变数组

Array为不可变数组,Array可以通过new的方式创建数组,也可以通过伴生对象创建。

数组的遍历:arr.foreach(print)

数组的合并:Array.concat(arr1, arr2)

创建并填充指定数量的数组:Array.fill [Int] (5)(-1)

5.1.2 可变数组

ArrayBuffer。

数据增加: buffer.append(1,2,3,4)

数据修改: buffer.update(0,5) //0表示索引 ;buffer(1) = 6

数据删除:buffer.remove(2); buffer.remove(2,2)

  • 可变数组 -->不可变数组 : buffer.toArray
  • 将不可变数组转换为可变数组: array.toBuffer

5.2 Seq集合

5.2.1 不可变List

List是抽象的,不能new,只能用伴生对象创建。

空集合: val list2: List[Nothing] = List() 等同于Nil集合

连接集合:List.concat(list3, list4)

创建一个指定重复数量的元素列表: List.fill [String] (3)(“a”)

5.2.2 可变List

ListBuffer。

增加数据:append方法或者buffer1 :+ 5、buffer1 += 5

可变集合转变为不可变集合: buffer.toList

不可变集合转变为可变集合:list.toBuffer

5.3 Set集合

5.3.1 不可变Set

5.3.2 可变Set

mutable.Set。

可变Set创建:mutable.Set(1,2,3,4); new mutable.Set()

增加数据:set1.add(5)

添加数据,更新完成以后包含: set1.update(6,true)

删除数据,更新完成以后不包含: set1.update(3,false)

删除数据: set1.remove(2)

遍历数据: set1.foreach(println)

5.4 Map集合

Map(映射)是一种可迭代的键值对(key/value)结构。所有的值都可以通过键来获取。Map 中的键都是唯一的。Map中的数据都是元组。

5.4.1 不可变Map

创建: val map1 = Map( “a” -> 1, “b” -> 2, “c” -> 3)

添加数据: map1 +(“d” -> 4)

创建空集合: Map.empty

获取指定key的值: map1.apply(“c”)

获取可能存在的key值: val maybeInt: Option[Int] = map1.get(“c”)

获取可能存在的key值, 如果不存在就使用默认值: println(map1.getOrElse(“c”, 0))

5.4.2 可变Map

val map1 = **mutable.**Map( “a” -> 1, “b” -> 2, “c” -> 3 )

添加数据: map1.put(“d”, 4)

修改数据: map1.update(“a”,8)

删除数据: map1.remove(“a”)

Map可以转换为其他数据类型:map1.toSet、 map1.toList、map1.toSeq、map1.toArray

获取可能存在的key值, 如果不存在就使用默认值: println(map1.getOrElse(“c”, 0))

5.5 元组

在Scala语言中,我们可以将多个无关的数据元素封装为一个整体,这个整体我们称之为:元素组合,简称元组。有时也可将元组看成容纳元素的容器

创建元组,使用小括号: val tuple = (1, “zhangsan”, 30)

根据顺序号访问元组的数据:println(tuple._1)

迭代器: val iterator: Iterator[Any] = tuple.productIterator

根据索引访问元素: tuple.productElement(0)

​ 如果元组的元素只有两个,那么我们称之为对偶元组,也称之为键值对: val kv: (String, Int) = (“a”, 1)

5.6 常用方法

  • 常用方法
object ScalaCollection{
    def main(args: Array[String]): Unit = {
        val list = List(1,2,3,4)

        // 集合长度
        println("size =>" + list.size)
        println("length =>" + list.length)
        // 判断集合是否为空
        println("isEmpty =>" + list.isEmpty)
        // 集合迭代器
        println("iterator =>" + list.iterator)
        // 循环遍历集合
        list.foreach(println)
        // 将集合转换为字符串
        println("mkString =>" + list.mkString(","))
        // 判断集合中是否包含某个元素
        println("contains =>" + list.contains(2))
        // 取集合的前几个元素
        println("take =>" + list.take(2))
        // 取集合的后几个元素
        println("takeRight =>" + list.takeRight(2))
        // 查找元素
        println("find =>" + list.find(x => x % 2== 0))
        // 丢弃前几个元素
        println("drop =>" + list.drop(2))
        // 丢弃后几个元素
        println("dropRight =>" + list.dropRight(2))
        // 反转集合
        println("reverse =>" + list.reverse)
        // 去重
        println("distinct =>" + list.distinct)
    }
}

 

object ScalaCollection{
    def main(args: Array[String]): Unit = {
        val list = List(1,2,3,4)
        val list1 = List(3,4,5,6)

        // 集合头
        println("head => " + list.head)
        // 集合尾
        println("tail => " + list.tail)
        // 集合尾迭代
        println("tails => " + list.tails)
        // 集合初始化
        println("init => " + list.init)
        // 集合初始化迭代
        println("inits => " + list.inits)
        // 集合最后元素
        println("last => " + list.last)
        // 集合并集
        println("union => " + list.union(list1))
        // 集合交集
        println("intersect => " + list.intersect(list1))
        // 集合差集
        println("diff => " + list.diff(list1))
        // 切分集合
        println("splitAt => " + list.splitAt(2))
        // 滑动 : 窗口
        println("sliding => " + list.sliding(2))
        // 滚动  有步长的滑动窗口
        println("sliding => " + list.sliding(2,2))
        // 拉链
        println("zip => " + list.zip(list1))
        // 数据索引拉链
        println("zipWithIndex => " + list.zipWithIndex)
    }
}
object ScalaCollection{
    def main(args: Array[String]): Unit = {
        val list = List(1,2,3,4)
        val list1 = List(3,4,5,6)

        // 集合最小值
        println("min => " + list.min)
        // 集合最大值
        println("max => " + list.max)
        // 集合求和
        println("sum => " + list.sum)
        // 集合乘积
        println("product => " + list.product)
        // 集合简化规约
        println("reduce => " + list.reduce((x:Int,y:Int)=>{x+y}))
        println("reduce => " + list.reduce((x,y)=>{x+y}))
        println("reduce => " + list.reduce((x,y)=>x+y))
        println("reduce => " + list.reduce(_+_))
        // 集合简化规约(左)  简约的数据类型可以不一样 op: (B, Int) => B ,参数B和Int有关系,泛型
        println("reduceLeft => " + list.reduceLeft(_+_))
        // 集合简化规约(右)
        println("reduceRight => " + list.reduceRight(_+_))
        // 集合折叠
        /**
            fo1d方法存在两数柯里化,有2个参数列表
第一个参数列表中的参数=z : AI  【z为zero,表示数据的初始值】
第二个参数列表中的参数=> (AI, A1)=>A1
*/
        println("fold => " + list.fold(0)(_+_))
        // 集合折叠(左)
        println("foldLeft => " + list.foldLeft(0)(_+_))
        // 集合折叠(右)
        println("foldRight => " + list.foldRight(0)(_+_))
        // 集合扫描  类似于fold方法,会将之间计算的结果保留下来
        println("scan => " + list.scan(0)(_+_))
        // 集合扫描(左)
        println("scanLeft => " + list.scanLeft(0)(_+_))
        // 集合扫描(右)
        println("scanRight => " + list.scanRight(0)(_+_))
    }
}
object ScalaCollection{
    def main(args: Array[String]): Unit = {
        val list = List(1,2,3,4)

        // 集合映射
        println("map => " + list.map(x=>{x*2}))
        println("map => " + list.map(x=>x*2))
        println("map => " + list.map(_*2))
        // 集合扁平化
        val list1 = List(
            List(1,2),
            List(3,4)
        )
        println("flatten =>" + list1.flatten)
        // 集合扁平映射
        println("flatMap =>" + list1.flatMap(list=>list))
        // 集合过滤数据
        println("filter =>" + list.filter(_%2 == 0))
        // 集合分组数据
        println("groupBy =>" + list.groupBy(_%2))
        // 集合排序
        println("sortBy =>" + list.sortBy(num=>num)(Ordering.Int.reverse))
        println("sortWith =>" + list.sortWith((left, right) => {left < right}))
    }
}

六、模式匹配

6.1 基本语法

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

6.2 匹配规则

6.2.1 匹配常量

def describe(x: Any) = x match {
    case 5 => "Int five"
    case "hello" => "String hello"
    case true => "Boolean true"
    case '+' => "Char +"
}

6.2.2 匹配类型

类型的匹配不考虑泛型。

def describe(x: Any) = x match {
    case i: Int => "Int"
    case s: String => "String hello"
    case m: List[_] => "List"  //下划线在泛型中表示任意类型
    case c: Array[Int] => "Array[Int]"
    case someThing => "something else " + someThing  //相当于下划线,其他任何类型
}

6.2.3 匹配数组

for (arr <- Array(Array(0), Array(1, 0), Array(0, 1, 0), Array(1, 1, 0), Array(1, 1, 0, 1), Array("hello", 90))) { // 对一个数组集合进行遍历
    val result = arr match {
        case Array(0) => "0" //匹配Array(0) 这个数组
        case Array(x, y) => x + "," + y //匹配有两个元素的数组,然后将将元素值赋给对应的x,y
        case Array(0, _*) => "以0开头的数组" //匹配以0开头和数组
        case _ => "something else"
    }
    println("result = " + result)
}

6.2.4 匹配列表

for (list <- Array(List(0), List(1, 0), List(0, 0, 0), List(1, 0, 0), List(88))) {
    val result = list match {
        case List(0) => "0" //匹配List(0)
        case List(x, y) => x + "," + y //匹配有两个元素的List
        case List(0, _*) => "0 ..."
        case _ => "something else"
    }

    println(result)
}

6.2.5 匹配元组

for (tuple <- Array((0, 1), (1, 0), (1, 1), (1, 0, 2))) {
    val result = tuple match {
        case (0, _) => "0 ..." //是第一个元素是0的元组
        case (y, 0) => "" + y + "0" // 匹配后一个元素是0的对偶元组
        case (a, b) => "" + a + " " + b
        case _ => "something else" //默认
    }
    println(result)
}

6.2.6 匹配对象& 样例类

Scala中模式匹配对象时,会自动调用对象的unapply方法进行匹配

这里的匹配对象,其实匹配的是对象的属性是否相同

class User(val name: String, val age: Int)
object User{
    def apply(name: String, age: Int): User = new User(name, age)
    def unapply(user: User): Option[(String, Int)] = {
        if (user == null)
            None
        else
            Some(user.name, user.age)
    }
}

val user: User = User("zhangsan", 11)
val result = user match {
    case User("zhangsan", 11) => "yes"
    case _ => "no"
}

一般使用样例类

  • l 样例类就是使用case关键字声明的类
  • l 样例类仍然是类,和普通类相比,只是其自动生成了伴生对象,并且伴生对象中自动提供了一些常用的方法,如apply、unapply、toString、equals、hashCode和copy。
  • l 样例类是为模式匹配而优化的类,因为其默认提供了unapply方法,因此,样例类可以直接使用模式匹配,而无需自己实现unapply方法。
  • l 构造器中的每一个参数都默认为val,除非它被显式地声明为var(不建议这样做)
  • l 样例类自动实现序列化
case class User(name: String, age: Int) //样例类

object ScalaCaseClass {
    def main(args: Array[String]): Unit = {
        val user: User = User("zhangsan", 11)
        val result = user match {
            case User("zhangsan", 11) => "yes"
            case _ => "no"
        }

        println(result)
    }
}

七、隐式转换

Scala在程序编译错误时,可以通过隐式转换中类型转换机制尝试进行二次编译,将本身错误无法编译通过的代码通过类型转换后编译通过。慢慢地,这也形成了一种扩展功能的转换机制。

​ 这里的隐式转换其实就是让编译器查找转换规则。需要使用关键字implicit

​ 隐式转换的使用:

​ 1、程序因为意外的情况,导致正常的逻辑出现错误

​ 2、扩展功能

7.1 隐式函数

通过创建隐式函数,完成一些不能进行进行类型转换的类型转换

implicit def transform( d : Double ): Int = {
            d.toInt
        }
var d : Double = 2.0
val i : Int = d    //正常情况下,Double 无法转换为 Int,但是隐式的调用了transform完成了类型的转换
println(i)
1

如果有多个相同转换规则怎么办?

转换无法成功,因为编译器无法识别用哪一个

7.2 隐式参数 & 隐式变量

含有隐式参数的方法,在调用时如果不使用小括号,那么表示使用隐式变量,如果使用小括号,那么表示放弃使用隐式变量

implicit修饰函数的参数时。这个参数所在的参数列表只能有一个参数

def regUser ( name :String) (implicit password:String =" 123123" ): Unit = {  //隐式参数
print1n(s" 注册用户: $name, 默认密码: $password")
}
//隐式变量
implicit val pswd:String =“888888”
//如果使用隐式参数进行处理,那么调用函数时,不需要使用小括号调用
regUser(“zhangsan” )   //此时password = 888888
//如果使用小括号,隐式变量无法使用
regUser(“zhangsan” ) ()    //此时password = 123123
regUser(“zhangsan” ) ("66666")    //此时password = 66666
//implicit修饰函数的参数时。这个参数所在的参数列表只能有一个参数

7.3 隐式类

​ 在Scala2.10后提供了隐式类,可以使用implicit声明类,隐式类非常强大,同样可以扩展类的功能,在集合的数据处理中,隐式类发挥了重要的作用。

其所带的构造参数有且只能有一个,可以使用柯里化

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。

object ScalaImplicit {
    def main(args: Array[String]): Unit = {
        val emp = new Emp()
        emp.insertUser()  //使用隐式类完成类型的隐式转换,直接进行了类的功能的扩展
    }
    class Emp {
    }
    implicit class User( emp : Emp) {   //隐式类,
        def insertUser(): Unit = {
            println("insert user...")
        }
    }
}

7.4 隐式机制

所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则

  • 当前代码作用域
  • 当前代码上级作用域
  • 当前类所在的包对象
  • 当前类(对象)的父类(父类)或特质(父特质)

其实最直接的方式就是直接导入。

**

def regUser ( name :String) (implicit password:String =" 123123" ): Unit = {  //隐式参数
print1n(s" 注册用户: $name, 默认密码: $password")
}
//隐式变量
implicit val pswd:String =“888888”
//如果使用隐式参数进行处理,那么调用函数时,不需要使用小括号调用
regUser(“zhangsan” )   //此时password = 888888
//如果使用小括号,隐式变量无法使用
regUser(“zhangsan” ) ()    //此时password = 123123
regUser(“zhangsan” ) ("66666")    //此时password = 66666
//implicit修饰函数的参数时。这个参数所在的参数列表只能有一个参数

7.3 隐式类

在Scala2.10后提供了隐式类,可以使用implicit声明类,隐式类非常强大,同样可以扩展类的功能,在集合的数据处理中,隐式类发挥了重要的作用。

其所带的构造参数有且只能有一个,可以使用柯里化

隐式类必须被定义在“类”或“伴生对象”或“包对象”里,即隐式类不能是顶级的。

object ScalaImplicit {
    def main(args: Array[String]): Unit = {
        val emp = new Emp()
        emp.insertUser()  //使用隐式类完成类型的隐式转换,直接进行了类的功能的扩展
    }
    class Emp {
    }
    implicit class User( emp : Emp) {   //隐式类,
        def insertUser(): Unit = {
            println("insert user...")
        }
    }
}

7.4 隐式机制

所谓的隐式机制,就是一旦出现编译错误时,编译器会从哪些地方查找对应的隐式转换规则

  • 当前代码作用域
  • 当前代码上级作用域
  • 当前类所在的包对象
  • 当前类(对象)的父类(父类)或特质(父特质)

其实最直接的方式就是直接导入。
 

  • 5
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值