1.模式匹配和样例类
1)模式匹配
Scala是没有Java中的switch case语法的,相对应的,Scala提供了更加强大的match case语法,即模式匹配,来替代switch case,match case也被称为模式匹配
match case的语法如下:
变量 match { case 值 => 代码 }
如果值为下划线“_”,则代表了不满足以上所有情况下的默认情况如何处理。
此外,match case中,只要一个case分支满足并处理了,就不会继续判断下一个case分支了。(与Java不同,java的switch case需要用break阻止)
(1)样例类匹配
样例类是一种特殊的类,可用于模式匹配,case class是多例的,后面要跟构造参数,case object是单例的。
带守卫的模式,增加布尔表达式或者条件表达式使得匹配更具体
//定义样例类
abstract class Notification
case class Email(sender:String,title:String)extends Notification
case class SMS(caller:String,message:String)extends Notification
case class VoiceRecording(contactName:String,link:String)extends Notification
//基于样例类的模式匹配
object CaseClassDemo2 {
def showNotification(notification: Notification)={
notification match {
case Email(sender,title) => s"$sender+ '---' + $title"
case SMS(caller,msg) => s"you get an $msg from $caller"
case VoiceRecording(name,link) => s"you get info from $name"
case _ =>println("other message")
}
}
def main(args: Array[String]): Unit = {
val email = Email("kate","email info")
println(showNotification(email))
}
}
(2)类型匹配
Scala的模式匹配一个强大之处就在于,可以直接匹配类型,而不是值
注意: 当你在匹配类型的时候,必须给出一个变量名,否则你将会拿对象本身来进行匹配
val arr = Array("hs", 1, 2.0, 'a')
val obj = arr(Random.nextInt(4))
println(obj)
obj match {
case x: Int => println(x)
case s: String => println(s.toUpperCase)
case _: Double => println(Int.MaxValue)
case _ => 0
}
(3)匹配字符串
/**
* 模式匹配-字符串
*/
object MatchString {
def main(args: Array[String]): Unit = {
val arr = Array("zhoudongyu", "yangzi", "guanxiaotong", "zhengshuang")
val name = arr(Random.nextInt(arr.length))
println(name)
name match {
case "zhoudongyu" => println("周冬雨")
case "yangzi" => println("杨紫")
case "guanxiaotong" => println("关晓彤")
case "zhengshuang" => println("郑爽")
case _ => println("Nothing ...")
}
}
}
(4)数组匹配
object ArrayMatch {
//数组匹配
def main(args: Array[String]): Unit = {
val arr = Array(1,2)
val res = arr match {
//匹配数组中只有某个元素:元素0
case Array(0) =>"0"
//匹配任何一个含有两个元素的数组,并将元素绑定到x和y
case Array(x,y) =>s"$x,$y"
//匹配第一个元素是0 的数组
case Array(0,_*) =>"0......."
//匹配不上时
case _ =>"no match"
}
println(res)
}
}
(5)列表匹配
object ListMatch {
//列表匹配 ::
def main(args: Array[String]): Unit = {
val list = List(0,1,2)
val res = list match{
//只包含某个元素(元素0)
case 0 :: Nil =>"0"
//包含两个元素的列表
case x::y::Nil =>x+"***"+y
//以0开始
case 0::tail =>"0*****"
}
println(res)
}
}
(6)元组匹配 ###
object TupleMatch {
def main(args: Array[String]): Unit = {
val tuple = (3,2)
val res = tuple match {
case (0,_) => "0 and other"
case (y,0) => s"$y+other and 0"
case (m,n) => s"$m ,$n+match"
case _ => "no match"
}
println(res)
}
}
2)样例类
定义一个样例类:
1). 构造器中的参数如果不显示指定为var,默认val类型
2). 样例类是一种类,会自动生成很多方法,提供apply方法 ,提供unapply方法,让你不使用new关键字就能构造出相应的对象,生成toString equals hashCode copy 方法,让模式匹配可以工作,除非显示给出这些方法的定义用样例类进行模式匹配
class CaseClassDemo {
val point1 = Point(1,2)
val point2 = Point(1,2)
val point3 = Point(2,2)
//比较样例类
//提供了equal方法
if(point1==point2){
println("the same")
}else{
println("different")
}
println(point1.x)
//point1.x=10 因为默认为val类型 所以不能修改值
point1.x=10
}
2.Option类型
在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。Some包装了某个值,None表示没有值
//OPtion -- some none
object OptionDemo {
def main(args: Array[String]): Unit = {
val map = Map("a"->1,"b"->2)
//模式匹配
val value = map.get("a") match{
case Some(elem) => elem
case None =>0
}
println(map.get("a")) //Some(1) 不能直接用,必须模式匹配去取
println(value) //1
println(map.get("a").get)//1 不匹配时会出错
val value2 = map.getOrElse("a",0) //1
println(value2)
}
}
注意使用map.getOrElse
3.偏函数
被包在花括号内没有match的一组case语句是一个偏函数,它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配
object PartialFunDemo {
//定义一个偏函数,其实创建了PartialFunction的一个实例
def fun:PartialFunction[String,Int] = {
case "one" =>1
case "two" =>2
case _=> 0
}
//不能去掉 :PartialFunction[String,Int]
def main(args: Array[String]): Unit = {
println(fun.isDefinedAt("three"))
println(fun.apply("one"))//做匹配
println(fun("one")) //与上面等价,调用的是fun.apply("one")
}
}
4.插值器
用途:处理字符串类型:
s:字符串插值 :(s"Hello,$name) ,使之在子字符串中可以使用变量或者表达式
字符串插值的位置也可以放表达式:s"1 + 1 = 1+1")f:插值并格式化输出插值f可以对字符串进行格式化,类似printf:f"{1 + 1}") f:插值并格式化输出 插值f 可以对字符串进行格式化,类似printf:f"1+1")f:插值并格式化输出插值f可以对字符串进行格式化,类似printf:f"name%s is $height%2.2f meters tall"
raw:对字符串不作任何变换的输出:raw"a\nb"
object StringInterDemo {
def main(args: Array[String]): Unit = {
//在子字符串中可以使用变量或者表达式
val names = "tom"
println(s"hello $names")
println(s"hello ${1+1}")
println(s"random,${Random.nextBoolean()}")
//f差值器。类似于printf 对输出内容格式化
val height = 1.9d
val name = "jerry"
println(f"$name%s is $height%6.2f meters tall")
//raw差值器
println(s"a\nb")
//raw差值器对转义符不处理
println(raw"a\nb")
}
}
5.文件以及正则表达式
(1)文件操作:
object FileDemo {
//文件读取
def main(args: Array[String]): Unit = {
//读取行
val source = Source.fromFile("C:\\Users\\brz\\Desktop\\mkdir\\Java面向对象.md")
//返回的是一个文件的迭代器
// val lines = source.getLines()
// for (line <-lines)
// println(line)
// //读取内容保存到Array
// val lines2 = source.getLines().toArray
// for (line <-lines2)
// println(line)
// //文件内容直接转换成一个字符串
// val contents = source.mkString
// println(contents)
// //读取文件,按字符
// for(c<-source)
// println(c)
// //读取文件为一个单词的数组
// var words = source.mkString.split(",")
//读取网络文件
val src = Source.fromURL("http://baidu.com")
val wline = src.getLines()
for (line <- wline)
println(line)
//写文件 writeFile
def writeFile ={
val out = new PrintWriter("temp.txt")
for (i <-1 to 100) out.println(i)
out.close()
}
}
}
(2) 正则表达式组
分组可以让我们方便地获取正则表达式的子表达式。在你想要提取的子表达式两侧加上圆括号
object RegexDemo extends App{
//数字和字母的组合正则表达式
val numitemPattern="""([0-9]+) ([a-z]+)""".r
val line="666 spark"
for(numitemPattern(num,item) <- numitemPattern.findAllIn(line)){
println(num+"\t"+item)
}
line match{
case numitemPattern(num,item)=> println(num+"\t"+item)
case _=>println("Nothing matched")
}
}
6.高阶函数
概念:如果一个函数的传入参数为函数或者返回值是函数,则该函数即为高阶函数。
高阶函数可以:传入参数为函数、传入参数为匿名函数、传入参数为方法、返回值为函数
object HighOrderFun {
//高阶函数 map filter sortwith
def main(args: Array[String]): Unit = {
//返回值是函数
def urlBuilder(ss1:Boolean,domainName:String):(String,String)=>String={
val schema = if (ss1)"https://" else "http://"
(endPoint:String,query:String)=>s"$schema$domainName/$endPoint?$query"
}
val domainName = "www.baidu.com"
def getUrl = urlBuilder(ss1=true,domainName) //用一个变量接收匿名函数,通过变量名去接收函数
val endpoint = "8080"
val query = "user='tom' "
val res = getUrl(endpoint,query)
print(res)
}
}
7.方法的嵌套
方法里嵌套定义其他方法
//方法的嵌套,方法里面可以定义其他方法
object InnerFun {
def factorial(x:Int):Int = {
def fact(x:Int,accumulator:Int):Int={
if(x <= 1) accumulator
else fact(x-1,x*accumulator)
}
fact(x,1)
}
def main(args: Array[String]): Unit = {
println(factorial(3))
}
}
8.方法的多态
Scala里方法可以通过类型实现参数化,类似泛型
//多态
object multiDemo {
def listOfDup[A](x:A,length:Int):List[A]={
if (length < 1)
Nil
else
x::listOfDup(x,length-1)
}
def main(args: Array[String]): Unit = {
println(listOfDup[Int](10,5))
println(listOfDup[String]("scala",5))
}
}
9.闭包
闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
函数体内可以方法相应作用域内的任何变量。
闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
val multiplier = (i:Int)=>i*10
val factor =5
val multiplier = (i:Int)=>i*factor
multiplier(10)
val factor =50
multiplier(10) 值不会变
10.柯里化
柯里化是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。
def curriedSum(x:Int)(y:Int)=x+y
curriedSum(1)(2)
curriedSum(1)_
val fun1=curriedSum(1)_
fun1(2)
可以分步去调用函数
11. 隐式转换
概念:隐式转换和隐式参数是Scala中两个非常强大的功能,利用隐式转换和隐式参数,你可以提供优雅的类库,对类库
的使用者隐匿掉那些枯燥乏味的细节。
作用:隐式的对类的方法进行增强,丰富现有类库的功能
1)隐式方法
implicit def DoubleToInt(x:Double)={x.toInt} //定义一个Double->Int的隐式转换的方法
scala> 1.2.toInt
res81: Int = 1
对系统的类或者自己定义的类用隐式转换进行扩展(扩展已有的类),隐式转换不需要调用
2)隐式参数
隐式参数,自动调用隐式值
def add(x:Int)(y:Int) = x+y
def add(x:Int)(implicit y:Int) = x+y
implicit val a = 10//设置隐式参数
add(1)
add(1)(20)
3)隐式类
使用implicit关键字,隐式类只能在类,接口,对象去定义,只能有一个构造参数,增强构造参数所表示的类型的方法
import Helper._
object Helper{
//对Int类进行一个加强
//使用implicit关键字,隐式类只能在类,接口,对象去定义,只能有一个构造参数,增强构造参数所表示的类型的方法
implicit class IntWithTimes(x:Int){
def times[A](f: =>A)={
def loop(current:Int):Unit={
if(current>0){
f
loop(current-1)
}
}
loop(x)
}
}
}
object ImplicitDemo {
def main(args: Array[String]): Unit = {
5 times(println("scala"))
}
}