Scala Day03
模式匹配
Scala 有一个十分强大的模式匹配机制,可以应用到很多场合:如 switch 语句、类型检查等。
并且 Scala 提供了样例类,对模式匹配进行了优化,可以快速进行匹配
匹配字符串
package com.scala.day03
import java.util.Random
/**
* 刚才所做的所有的操作都是为了 使用和体验 这个scala的语法
*/
object MatchTest {
def main(args: Array[String]): Unit = {
val list = List("a", "b", "c", "d")
var r = new Random()
// index值就是list的下标:可能为 0, 1, 2, 3
val index = r.nextInt(list.length)
// value就是从list中随机取到的一个值
val value = list(index)
println(value)
var result = value match {
// 如果value的值为"a", 执行{}中的代码
case "a" => {
println("a")
"a"
}
case "b" => {}
case "c" => {
println("匹配到字符串C")
1
}
// "_" 表示匹配任意的单个值;
case _ => {
println("else")
}
}
println(result)
}
}
匹配类型
package com.scala.day03
import java.util.Random
class Student
object MatchTest2 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 2f, 3D, true, "a", new Student())
var r = new Random()
// index值就是list的下标:可能为 0, 1, 2, 3
val index = r.nextInt(list.length)
// value就是从list中随机取到的一个值
val value = list(index)
println("value: \t" + value)
// 根据类型在匹配
// if x > 8 : 守卫条件
val result = value match {
// 表示匹配 大于8 的整数
case x: Int if x > 8 => println(" > 8", x)
case x: Int => println(" <= 8", x)
case x: Float => println(2, x)
case x: Double => println(3, x)
case x: Boolean => println(true, x)
case x: String => println("s", x)
// 类似java中 switch case中的default
case _ => println("else")
}
}
}
注意:case y: Double if(y >= 0) => ...
模式匹配的时候还可以添加守卫条件。如不符合守卫条件,将掉入 case _中
匹配数组、元组、集合
package com.scala.day03
import scala.collection.immutable.HashSet
object MatchTest3 {
def main(args: Array[String]): Unit = {
val list = List(1, 2, 3, 4, 5, 6, "abcd")
// val set = HashSet(1,2,3,4,5,6,"abcd")
val value = list
value match {
case 2 :: 3 :: Nil => {
println("List(2,3)")
}
case List(1, 2, 3, _, _, _, x) => println(x)
case 1 :: 2 :: x => {
println(x)
}
case _ => println("else")
}
}
}
注意:在 Scala 中列表要么为空(Nil 表示空列表)要么是一个 head 元素加上一个 tail 列表。
9 :: List(5, 2) :: 操作符是将给定的头和尾创建一个新的列表
注意::: 操作符是右结合的,如 9 :: 5 :: 2 :: Nil 相当于 9 :: (5 :: (2 :: Nil))
样例类
样例类 是一种特殊的类,可用于模式匹配
case class 是多例的,后面要更构造参数;case object是单例的
当一个类被声名为 case class 的时候,scala 会帮助我们做下面几件事情:
- 构造器中的参数如果不被声明为
var的话,它默认是 val 类型的,但一般不推荐将构造器中的参数声明为 var; - 自动创建伴生对象,同时在里面给我们实现子
apply方法,使得我们在使用的时候可以不直接显示地new对象 - 伴生对象中同样会帮我们实现
unapply方法,从而可以将case class应用于模式匹配apply方法接受参数返回对象,unapply方法接收对象返回参数 - 实现自己的
toString、hashCode、copy、equals方法 case class主构造函数里面没有修饰符,默认的是val
除此之此,case class 与其它普通的 scala 类没有区别
创建样例类
case class Student(id:Int,name:String)
创建的对象,默认就是val类型,并且是private修饰的
因此成员变量就需要用var修饰
创建样例对象
case object Student
样例对象是不能带有参数的
示例
```scala
package com.scala.day03
import java.util.Random
object MatchTest4 {
def main(args: Array[String]): Unit = {
val list: List[Any] = List(
Student4444(1, "a"),
Student5555(2, "b"),
Student6666
)
var r = new Random()
// index值就是list的下标:可能为 0, 1, 2, 3
val index = r.nextInt(list.length)
// value就是从list中随机取到的一个值
val value = list(index)
println("value: \t" + value)
value match {
case Student4444(id, name) => {
println("student4444")
println(id, name)
}
case Student5555(id, name) => {
println("student55555")
println(id, name)
}
case Student6666 => {
println("case object")
}
}
}
}
/**
* 这个case class 就是样例类, 作用,就是用来做模式匹配的
*
* 这个 case object的作用也类似
*/
case class Student4444(id: Int, name: String)
case class Student5555(id: Int, name: String)
case object Student6666
Option类型
在 Scala 中 Option 类型样例类用来表示可能存在或也可能不存在的值(Option 的子类有 Some和 None)。Some 包装了某个值,None 表示没有值
package com.scala.day03
object MapOptionTest {
val map = Map(("a", 1), ("b", 2), ("c", 3))
def main(args: Array[String]): Unit = {
var key: String = "d"
// println(map(key))
// println(map.get(key))
// println(map.getOrElse(key, "default"))
// println(find(map, key))
// println(getOrElse(map, key))
println(getOrElse2(key))
}
def find(map: Map[String, Int], key: String): Int = {
// Some(x) None
map.get(key)
return map.getOrElse(key, 0)
}
// 定义的一个非常普通的方法
def getOrElse(map: Map[String, Int], key: String): Int = {
// Some(x) Option中代表值存在的一个 子类
// None Option中代表值不存在的一个 子类
val result: Option[Int] = map.get(key)
val lastResult = result match {
case Some(x) => x
case None => 0
}
lastResult
}
// 利用模式匹配实现的一个方法
def getOrElse1(key: String) = {
map.get(key) match {
case Some(x) => x
case None => 0
}
}
// 模式匹配: 偏函数
// String, Int
// String: 输入的参数类型
// Int : 输出的类型
// 没有match关键字的一堆 case分支 组成的一个代码块就是一个偏函数
def getOrElse2: PartialFunction[String, Int] = {
case "a" => 1
case "b" => 2
case "c" => 3
case _ => 0
}
// 偏函数: 就是为了做模式匹配
}
偏函数
被包在花括号内没有 match 的一组 case 语句是一个偏函数,它是 PartialFunction[A, B]的一个实例,A 代表参数类型,B 代表返回值类型,常用作输入模式匹配
package day2.oop
object PartialFuncDemo {
//偏函数
def func1: PartialFunction[String, Int] = {
case "one" => 1
case "two" => 2
case _ => -1
}
//普通函数的模式匹配实现
def func2(num: String) : Int = num match {
case "one" => 1
case "two" => 2
case _ => -1
}
def main(args: Array[String]) {
println(func1("one"))
println(func2("one"))
}
}
高阶函数 和 闭包
因为方法和函数虽然定义不同,但是作用一样,也切也可以相互转化
所有以后统统都叫函数;
定义函数
有名函数
scala> val add =(x:Int,y:Int) =>{x+y}
add: (Int, Int) => Int = <function2>
scala> val array = List(1,2,3,4,4,5,6,7)
array: List[Int] = List(1, 2, 3, 4, 4, 5, 6, 7)
scala> array.reduce(add)
res6: Int = 32
匿名函数
scala> val array = List(1,2,3,4,4,5,6,7)
array: List[Int] = List(1, 2, 3, 4, 4, 5, 6, 7)
scala> array.reduce((x:Int,y:Int)=>{x+y})
res7: Int = 32
其他用法
scala> val array = List(1,2,3,4,4,5,6,7)
array: List[Int] = List(1, 2, 3, 4, 4, 5, 6, 7)
scala> array.map((x:Int)=>x+2)
res8: List[Int] = List(3, 4, 5, 6, 6, 7, 8, 9)
scala> array.map(x=>x+2)
res9: List[Int] = List(3, 4, 5, 6, 6, 7, 8, 9)
scala> array.map(_+2)
res10: List[Int] = List(3, 4, 5, 6, 6, 7, 8, 9)
scala> array.reduce(_+_)
res11: Int = 32
高阶函数
高阶函数:一个函数可以作为另外一个函数的参数或者返回值
- 函数作为参数
- 函数作为返回值
函数的返回值是函数
scala> def add(x:Int) = {(y:Int)=>x+y}
add: (x: Int)Int => Int
scala> val add2 = add(2)
add2: Int => Int = <function1>
scala> add2(4)
res12: Int = 6
scala>
函数的参数为另外一个函数
scala> def opt(f:(Int,Int)=>Int) = f(3,4)
opt: (f: (Int, Int) => Int)Int
scala> val add = (x:Int,y:Int) => x+y
add: (Int, Int) => Int = <function2>
scala> val max =(x:Int,y:Int)=>if(x>y)x else y
max: (Int, Int) => Int = <function2>
scala> opt(add)
res13: Int = 7
scala> opt(max)
res14: Int = 4
柯里化 Curry
柯里化(Currying)是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数且返回结果是一个新函数的技术。
柯里化函数与 高阶函数中返回值是函数的类型很像;
但是它必须同时将所有参数传递完;
package com.scala.day3
object CurryTest {
def multiply(x:Int)(y:Int) = x * y
//柯里化就是把参数可以分开来,把部分函数参数可以用下划线来代替
def multiply2 = multiply(2)_
// 一个普通的方法,接受两个 Int 类型参数做乘积
def multiply3(x:Int, y:Int) = x * y
def multiply4(x:Int, y:Int=10) = x * y
def multiply5(x:Int)(y:Int=10) = x * y
def main(args: Array[String]):Unit = {
println(multiply(2)(4))
println(multiply2(4))
// 跟柯里化的函数在结果上没有区别,那到底有什么区别呢?
println(multiply3(2,4))
println(multiply4(4))
println(multiply5(4)())
}
}
可以使用_ 代替第二个参数;从而变成高阶函数的样式
科里化的默认参数,可以隐式参数,也可以是默认参数;
// 默认参数
scala> def add1(x:Int)(y:Int=10) = x*y
add1: (x: Int)(y: Int)Int
scala> val result = add1(5)()
result: Int = 50
// 隐式参数
scala> def add1(x:Int)(implicit y:Int=10) = x*y
add1: (x: Int)(implicit y: Int)Int
scala> val result = add1(5)
result: Int = 50
默认参数
也就是在定义函数的时候,直接针对参数进行赋值;
但是柯里化函数的默认参数,必须是隐式的;
隐式参数
三个要点:
- 在一个代码运行环境中,相同类型的隐式变量只能存在一个
- 如果存在多个,那么请定义在一个自定义的object单例对象;必须是单例对象;
- 使用的时候,需要使用哪一个;就使用
import命令添加即可
工作机制:
- 默认,在方法的定义上,是有一个隐式参数默认值的
- 当环境中,引入了其他的相同类型的隐式变量的话,那么,首先从全局中,从系统中,寻找相同类型的隐式变量值,如果没有找到,则使用方法定义的默认的参数值;
隐式变量的工作,是按照类型匹配,并且一个代码运行环境汇总,不能出现二义性(不能同时存在多个相同类型的隐式变量)
_的应用场景
- 手动转换方法为函数
- 元组中,用来指定下标访问对应位置上的值
- 匹配模式中,表示其他任意情况
case _ - 变量的初始值:
var a:Int = _;var s:String=_ - map函数和reduce函数等系统函数中;可以使用
_代表某个元素,但是这个元素在具体的逻辑中只能够出现一次;
闭包
本质是可以访问一个函数里面局部变量的另外一个函数
package com.aura.scala.day03
object BibaoTest {
def main(args: Array[String]): Unit = {
// 闭包就是用来解决这个问题: 在一个函数的外部要访问这个函数内部的一个局部变量
def f1(x:Int):Int = {
var abc = 100
var sum:Int = 100
sum += x
abc += sum
sum
}
println(f1(100))
}
}
隐式转换
需要注意的是:
- 隐式转换只能定义在object中;
- 注意隐式转换的二义性
忠告:尽量不要使用隐式转换
应用场景
-
当调用某个对象不存在的方法的时候,会触发这个对象进行隐式转换
package com.scala.day03 import java.io.File import scala.io.Source object FileUtil { def main(args: Array[String]): Unit = { // 例如 Int类型 没有 to方法一样 // scala在处理的时候是将 Int转换为 RichInt类型了 // 可以通过 :implicits -v 查看 1.to(10) // 获取一个File对象 val file = new File("c:/words.txt") // 读取这个File对象代表的那个文件的全部内容 // 如果想让这个方法执行成功,那么必须利用scala的隐式转换的语法,让file对象转换成另外一个具备 // readAllContentXXXXXXXXXXXXXX这个方法的一个实例对象,即可! // 二义性: 此处不能导入MyImplicit123下的所有隐式转换;只能导入某一个隐式转换; import MyImplicit123.xxxxxxxx1 val allContent:String = file.readAllContentXXXXXXXXXXXXXX() println(allContent) } } // 这个隐式转换的定义,就是为了让 File 类型的对象,可以被转换为 RichFile 类型的对象 object MyImplicit123{ implicit def xxxxxxxx1(file:File):RichFile1 = new RichFile1(file) implicit def xxxxxxxx2(file:File):RichFile2 = new RichFile2(file) } // 这个组件 RichFile的作用,就是定义一个具备readAllContentXXXXXXXXXXXXXX // 这个方法的类 class RichFile1(val file:File){ def readAllContentXXXXXXXXXXXXXX(): String ={ Source.fromFile(file).mkString } } class RichFile2(val file:File){ def readAllContentXXXXXXXXXXXXXX(): String ={ Source.fromFile(file).mkString } } -
当调用某个方法时,传入的参数类型不匹配的时候,会触发参数变量进行隐式转换
// 可以当做 类型转换器来使用; package com.scala.day03 /** - 人 和 人 * - 人 和 狗 */ object MakeFriend { def main(args: Array[String]): Unit = { val huangbo = new Person("huangbo") val xuzheng = new Person("xuzheng") val wangcai = new Dog("wangcai") huangbo.makeFriend(xuzheng) import MyImplicit333.dog2Person huangbo.makeFriend(wangcai) /** * * 隐式转换有将Int转换为Double的,但是没有将Double转换为Int的; * 如果需要,则需要手动定义; */ val add:(Int,Int)=>Int = (x:Int,y:Int)=>x+y // 传入的参数是double类型的;此时就需要将double转化为Int类型的 add(5.0,4.0) } } object MyImplicit333 { implicit def dog2Person(dog: Dog): Person = { new Person(dog.name) } } // huangbo 和 xuzheng 交朋友 // val huangbo = new Person("huangbo") // val xuzheng = new Person("xuzheng") // huangbo.makeFriend(xuzheng) class Person(val name: String) { def makeFriend(p: Person): Unit = { println(this.name, p.name) } } class Dog(val name: String) { } -
在存在视图边界的时候
泛型
scala默认提供的隐式转换
scala> :implicits -v
/* 69 implicit members imported from scala.Predef */
/* 7 inherited from scala */
final implicit class ArrayCharSequence extends CharSequence
final implicit class ArrowAssoc[A] extends AnyVal
final implicit class Ensuring[A] extends AnyVal
final implicit class RichException extends AnyVal
final implicit class SeqCharSequence extends CharSequence
final implicit class StringFormat[A] extends AnyVal
final implicit class any2stringadd[A] extends AnyVal
/* 40 inherited from scala.Predef */
implicit def ArrowAssoc[A](self: A): ArrowAssoc[A]
implicit def Ensuring[A](self: A): Ensuring[A]
implicit def StringFormat[A](self: A): StringFormat[A]
implicit def any2stringadd[A](self: A): any2stringadd[A]
implicit def booleanArrayOps(xs: Array[Boolean]): mutable.ArrayOps[Boolean]
implicit def byteArrayOps(xs: Array[Byte]): mutable.ArrayOps[Byte]
implicit def charArrayOps(xs: Array[Char]): mutable.ArrayOps[Char]
implicit def doubleArrayOps(xs: Array[Double]): mutable.ArrayOps[Double]
implicit def floatArrayOps(xs: Array[Float]): mutable.ArrayOps[Float]
implicit def genericArrayOps[T](xs: Array[T]): mutable.ArrayOps[T]
implicit def intArrayOps(xs: Array[Int]): mutable.ArrayOps[Int]
implicit def longArrayOps(xs: Array[Long]): mutable.ArrayOps[Long]
implicit def refArrayOps[T <: AnyRef](xs: Array[T]): mutable.ArrayOps[T]
implicit def shortArrayOps(xs: Array[Short]): mutable.ArrayOps[Short]
implicit def unitArrayOps(xs: Array[Unit]): mutable.ArrayOps[Unit]
implicit def $conforms[A]: <:<[A,A]
implicit def ArrayCharSequence(__arrayOfChars: Array[Char]): ArrayCharSequence
implicit def Boolean2boolean(x: Boolean): Boolean
implicit def Byte2byte(x: Byte): Byte
implicit def Character2char(x: Character): Char
implicit def Double2double(x: Double): Double
implicit def Float2float(x: Float): Float
implicit def Integer2int(x: Integer): Int
implicit def Long2long(x: Long): Long
implicit def RichException(self: Throwable): RichException
implicit def SeqCharSequence(__sequenceOfChars: IndexedSeq[Char]): SeqCharSequence
implicit def Short2short(x: Short): Short
implicit val StringCanBuildFrom: generic.CanBuildFrom[String,Char,String]
implicit def augmentString(x: String): immutable.StringOps
implicit def boolean2Boolean(x: Boolean): Boolean
implicit def byte2Byte(x: Byte): Byte
implicit def char2Character(x: Char): Character
implicit def double2Double(x: Double): Double
implicit def float2Float(x: Float): Float
implicit def int2Integer(x: Int): Integer
implicit def long2Long(x: Long): Long
implicit def short2Short(x: Short): Short
implicit def tuple2ToZippedOps[T1, T2](x: (T1, T2)): runtime.Tuple2Zipped.Ops[T1,T2]
implicit def tuple3ToZippedOps[T1, T2, T3](x: (T1, T2, T3)): runtime.Tuple3Zipped.Ops[T1,T2,T3]
implicit def unaugmentString(x: immutable.StringOps): String
/* 22 inherited from scala.LowPriorityImplicits */
implicit def genericWrapArray[T](xs: Array[T]): mutable.WrappedArray[T]
implicit def wrapBooleanArray(xs: Array[Boolean]): mutable.WrappedArray[Boolean]
implicit def wrapByteArray(xs: Array[Byte]): mutable.WrappedArray[Byte]
implicit def wrapCharArray(xs: Array[Char]): mutable.WrappedArray[Char]
implicit def wrapDoubleArray(xs: Array[Double]): mutable.WrappedArray[Double]
implicit def wrapFloatArray(xs: Array[Float]): mutable.WrappedArray[Float]
implicit def wrapIntArray(xs: Array[Int]): mutable.WrappedArray[Int]
implicit def wrapLongArray(xs: Array[Long]): mutable.WrappedArray[Long]
implicit def wrapRefArray[T <: AnyRef](xs: Array[T]): mutable.WrappedArray[T]
implicit def wrapShortArray(xs: Array[Short]): mutable.WrappedArray[Short]
implicit def wrapUnitArray(xs: Array[Unit]): mutable.WrappedArray[Unit]
implicit def booleanWrapper(x: Boolean): runtime.RichBoolean
implicit def byteWrapper(x: Byte): runtime.RichByte
implicit def charWrapper(c: Char): runtime.RichChar
implicit def doubleWrapper(x: Double): runtime.RichDouble
implicit def fallbackStringCanBuildFrom[T]: generic.CanBuildFrom[String,T,immutable.IndexedSeq[T]]
implicit def floatWrapper(x: Float): runtime.RichFloat
implicit def intWrapper(x: Int): runtime.RichInt
implicit def longWrapper(x: Long): runtime.RichLong
implicit def shortWrapper(x: Short): runtime.RichShort
implicit def unwrapString(ws: immutable.WrappedString): String
implicit def wrapString(s: String): immutable.WrappedString
异常处理
与java一样,写法不同
try{
add(5.0,4.0)
}case e:IndexOutOfBoundsException{
}case e:ArrayIndexOutOfBoundsException{
}
泛型
泛型的作用:在编译期进行参数检查;防止在运行时出错;
泛型类:指定类可以接受任意类型参数。
泛型方法:指定方法可以接受任意类型参数。
scala类型变量界定
下界: T >: S 类似于java的 extends
上界: T <: S super
类型变量界定就是在泛型的基础上,对泛型的范围进一步的界定;从而缩小泛型的具体范围
package com.scala.day03
object XiaJieTest {
def main(args: Array[String]): Unit = {
// ceshi[Son](new Son())
ceshi[Father](new Father())
}
def ceshi[T >: Me](person: T): Unit ={
println("aaaaaa")
}
}
class GrandFather
class Father extends GrandFather
class Me extends Father
class Son extends Me
class Tongzhuo
scala视图界定
如果希望跨越类继承层次结构时,可以使用视图界定来实现的,其后面的原理是通过隐式转换来实现
视图界定利用<%符号来实现
package com.mazh.scala.day3
case class Student11[T,S <: Comparable[S]](var name:T,var height:S)
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
*/
object GenericTypeTest3{
def main(args: Array[String]): Unit = {
// 这是合法的语句
val s= Student11("john","170")
//下面这条语句不合法,这是因为,Int 类型没有实现 Comparable 接口
val s2= Student11("john",170)
}
}
修改以后的代码
package com.mazh.scala.day3
case class Student11[T,S <% Comparable[S]](var name:T,var height:S)
/**
* 作者: 马中华:http://blog.csdn.net/zhongqi2513
*/
object GenericTypeTest3{
def main(args: Array[String]): Unit = {
// 这是合法的语句
val s= Student11("john","170")
// Int 类型的变量经过隐式转换成了 RichInt 类型,RichInt 类型是实现了 Comparable 接口的
val s2= Student11("john",170)
}
}
分析:
利用<%符号对泛型 S 进行限定,它的意思是 S 可以是 Comparable 类继承层次结构中实现了Comparable 接口的类,也可以是能够经过隐式转换得到的实现了 Comparable 接口的类。
上面改动的语句在视图界定中是合法的,因为 Int 类型此时会隐式转换为 RichInt 类,而RichInt 类属于 Comparable 继承层次结构。Int 类会隐式转换成 RichInt 类,RichInt 并不是直
接实现 Comparable 口,而是通过 ScalaNumberProxy 类将 Comparable 中的方法继承过来。
scala的协变和逆变
协变
当类型 B 是类型 A 的子类型时,则 List[B]也可以认为是 List[A]的子类型,即 List[B]可以泛化为 List[A]
package com.aura.scala.day03
object XieBianTest {
def main(args: Array[String]): Unit = {
var o1 = new SSS[String]("aa")
var o2 = new SSS[Int](1)
// o2 = o1
var o3 = new SSS[AA](new AA())
var o4 = new SSS[BB](new BB())
var a = new AA()
var b = new BB()
a = b
// b = a
// StudentService ss = new StudentServiceImpl()
// StudentService ss = new StudentServiceImpl1()
// StudentService ss = new StudentServiceImpl2()
o3 = o4
// o4 = o3
// o3 的类型 一定要 >= o4 的类型
}
}
/**
* + 协变
* - 逆变
*/
class SSS[+T](val id:T){}
class AA
class BB extends AA
逆变
当类型 B 是类型 A 的子类型时,则 List[A]也可以认为是 List[B]的子类型,即 List[A]可以泛化为 List[B]


浙公网安备 33010602011771号