scala总结

本文详细介绍了Scala编程的基础知识,包括变量和常量的定义、基础语法、类型转换、表达式和循环结构、函数和方法、元组、集合操作、异常控制、泛型以及字符串插值等,帮助读者掌握Scala编程的基本概念和用法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

变量和常量的使用

关键字

var:定义的是变量,值是可以变化的

val:定义的是常量,值是不能变化的

基础语法

在scala中定义变量的时候,可以不带类型,由后面的值进行自动推导

  1. var variable = value

    不去指定variable的类型后面的值进行自动推导

2.var variable:Int

​ 使用指定的类型声明一个变量,此时前面声明的类型必须和后面的值类型一致

var a=10    //不设置类型,由值自动推导类型
var b:Int=0 //设置一个变量,手动指定类型,此时前后的类型需要一致
var n1,n2=10 //同时设置两个变量,两个变量类型和值相同
var (n3,n4)=(30,40)  //同时设置两个变量,两个变量的值不同
var (n5,n6,n7)=(10,"hello world",3.14)  //同时设置多个变量,多个变量的类型和值都不同

转义字符

val str2:String = "leetom: \"hello world\""

"""

以"""开头,以"""结尾,中间的部分不用做转义
val str3:String = """leetom: "hello world""""
"""中间是可以换行的
stripMargin可以解析一行的|开头
val str4:String = 
"""leetom: "say hello"
   |leejerry: "good day"
   |leetoy:"nice day"
   |""".stripMargin

语法糖

val name:String="leetom"
val age:Int = 18
val gender:Char = 'm'
println(s"我的名字是:$name,我的年龄是:$age,我的性别是:$gender")

类型转换

自动类型转换

val num1:Int=10
val num2:Long=num1

强制类型转换

val n1:Long=1000L
val n2:Byte=n1.toByte

数值类型转字符串类型

val s1:String = n2.toString

判断变量是否为指定类型

s1.isInstanceOf[String]

字符串转数值类型

val s2:String="123456"
val s3:Int=s2.toInt

算数运算符大部分和java相同

a.+(b)和a+b等价

代码块,一段可以执行的代码

//代码段
{
    代码段
    这里的代码会被执行
    除了有局部变量作用域限定,没有其他意义
}

表达式

val res0:Int={
    val a=10
    val b=20
    a+b
}
这段代码可以被求值
代码段中的最后一行的结果是个代码段执行的结果最后一个值前面不能添加return
res0的类型是由右侧的代码段结果进行自动推导

分支if else

val le1:Int={
    if(a>b)
        a
    else
        b
}

while循环

var sum=0
var num=0
while(num<=100){
    sum+=num
    num+=1
}

do while循环

sum=0
num=1
do{
    sum+=num
    num+=1
}while(num<=100)

for循环

to:1 to 100 生成区间[1:100]

until:1 until 100 生成区间[1,100)

基础语法

for(变量<-区间)

使用区间的每一个值依次给变量赋值

for(a<-1 to 3){}

嵌套循环一次建每一层的循环条件在一个for的的小括号中写出来,用分号分隔

for(a<-1 to 3;b<-1 to 3){}

循环推导式

将每次循环得到的值放在yield后面

val res:immutable.Seq[Int] = for(i<-1 to 50 if i%2==0 && i%3==0) yield i 

scala中的break

scala中没有break和continue
可以使用breakable
导入包
import scala.until.control.Breaks._
breakable{
    for(i<-1 to 100){
        println(i)
        if(i==5)
            break
    }
}

方法

定义的时候方法的返回值类型可以不写,由实际的返回值进行推导

但是递归调用方法的到时候这个方法的返回值必须明确

如果方法体重的逻辑很简单,只有一行,大括号可以省略不写 推荐省略不写

如果一个方法是无参方法,调用的时候可以不写小括号

如果一个方法时无参的,在定义的时候可以省略小括号不写,在调用的时候也能不写小括号

def calculate(a:Int,b:Int):Int = a+b
定义方法时,可以不写等号
如果不定义等号不会通过右边的方法体的结果,来自动推导的方法的返回类型
def myMethod(){
    val a=10
    val b=10
    a+b
}

调用方法的时候可以使用带名参数

//定义方法的时候可以允许参数是有默认值的
//默认参数调用的时候可以不进行值的设置
def calculate(x:Int,y:Int,z:Int=10):Int={
    x+y+z
}
//有默认值的参数,在调用的时候默认传递的值其实是按照顺序进行赋值的
def calculate2(x:Int=20,y:Int,z:Int=30):Int+{
    x+y+z
}
calculate(5,10)
​
调用方法的时候传参的时候可以使用带名参数
calculate2(y=20)
calculate2(y=5,z=10,x=20)

在java里变长参数可以传递一个数组值,但在scala中是不允许的

def getSum(numbers:Int*):Int={
    //在scala中变长参数的类型也是数组的类型
    varsum=0
    for(n<-numbers){
        sum+=n
    }
    sum
}
​
getSum(array:_*)

函数

函数和方法的区别

语法区别

方法:def 方法名字(参数列表):返回值类型={方法体}

函数:val 函数变量:函数类型(可以不设置)=(函数的参数列表)=>{函数体}

位置不同

方法:一般定义在类内,特质内,包括在某一个object内

函数:一般定义在类内,特质内,object内,方法内

def calculate(calculator:(Int,Int)=>Int,x:Int,y:Int):Unit={
    println(calculator(x,y))
}
def calculateMethod(x:Int,y:Int):Int=x+y
​
//定义一个scala函数需要依靠某一个变量的值,将这个函数给某一个变量赋值
val calcultor=(a:Int,b:Int)=>a+b
calcultor(10,20)
//如果左侧函数的变量类型已经确定,可以不写参数类型
val calculator2:(Int,Int)=>Int=(x,y)=>x+y
//如果参数只用到一次,在实现部省略参数声明部分用_代替
val calculator3:Int=>Unit=println(_)
val calculator4:Int=>Int=_*2
val calculator5:(Int,Int)=>Int=_+_
val calculator6:(Int,Int,Int)=>Int=_+_+_
//如果函数的实现中使用_来表示唯一使用到的参数且这个参数作为另一个函数或方法出现,此时可以省略掉这个下划线和方法或者参数的小括号
val calculator7:Int=>Unit=println(_)
val calculator8:Int=>Unit=println
val calculator9:(Int,Int)=Int=>calculateMethod
//高阶函数就是将参数或者返回值设置为其他的函数,就是一个高阶函数
calculate(_+_,10,20)
calculate(calculator5,100,200)
calculate(calculateMethod,100,200)
val cal:((Int,Int)=>Int,Int,Int)=>Int=_(_,_)
cal(_+_,100,200)
//方法转函数直接在后面加一个空格下划线即可
val calculator10=calculateMethod _
​

在scala中集合大概分为scala.collection.immutable和scala.collection.mutable

scala默认采用的是immutable的

mkString:将一个集合中的元素拼接成一个字符串

​ -()=>将所有的元素拼接成一个字符串

​ -(sep:String)=>将所有的元素拼接到一起,中间使用指定的分隔符 分隔

​ -(start:String,sep:String,end:String)=>将所有的元素拼接到一起,使用sep分隔 前缀start,后缀end

创建数组

val array1=new Array[Int](10)
println(array1.mkString)
println(array1.mkString(","))
println(array1.mkString("[",",","]"))
​
val array2=Array[Int](1,2,3,4,5,6,7,8,9)

获取数组元素

println(array2(3)) //下标获取使用()写下标

通过下标修改元素

array2(3)=45

增强for遍历数组

for(ele<-array2){
    println(ele)
}

下标遍历数组

//数组中有一个现成的方法可以使用.indices,可以获取一个数组的下标范围
for (index<-array2.indices){
    println(....)
}

可变数组ArrayBuffer

添加一个元素

val array=new ArrayBuffer[Int]()
array+=1

添加多个元素

array+=(2,3,4,45)

添加一个集合的元素

array++=array

删除一个元素(只会删除从前往后的第一个匹配项)

array-=1

删除多个元素

array-=(2,3,4,5,6)

删除一个集合中的元素

val arr=Array(1,3,4)
array--=arr

使用方法追加多个元素

array.append(10,20,30,40)

将一个集合中的元素追加到当前集合中

array.appendAll(arr)

在指定的下标插入一个元素

array.insert(3,100)

删除数组中的最后三个元素

array.trimEnd(3)

删除数组中的前三个元素

array.trimStart(3)

删除数组中的指定下标位的元素

array.remove(2)

删除数组中的指定下标位开始,指定数量的位置

array.remove(1,2)

ArrayBuffer转成Array

val array1=array.toArray

Array转成ArrayBuffer

val buffer=array1.toBuffer

数组中常用的方法

array.max
array.min
array.sum
array.sorted
array.sortWith(_ < _)//前面元素小于后面的元素
array.sortWith(_ > _)//前面的元素大于后面的元素

懒加载

lazy:叫懒加载
声明的时候并不会执行,当用到这个变量的时候才会执行
只能修饰val
lazy val number = {
    print(...)
    10
}

控制台输入

val str:String= StdIn.readLine()

异常控制

def exceptionTest():Unit={
    try{
        val num = 10/0
    }catch{
        case e:ArithmeticExcption=> println("算数异常")
        case e:Exception=> pritnln("其他异常")
    }
}

元组

元组是一个类似一维数组的容器,但是和数组是不一样的

元组中可以存储任意类型的元素

元组的定义,直接用小括号即可

元组的元素访问,也通过类似下标的方式

定义元组

val tuple1:(Int,String,Double,Boolean)=(1,"hello",3.14,false)
val tuple2:(String,Int)=("hello",1)
val tuple3:(Int)=(1)

访问元组中的元素

tuple1._1
tuple1._2
tuple1._3
tuple1._4

下标方式访问元组,从0开始

tuple1.productElement(0)
tuple1.productElement(1)
tuple1.productElement(2)
tuple1.productElement(3)

元组的遍历

for(ele <- tupel1.productIterator){
    print(...)
}

tuple1.productIterator.foreach(println)

拉链

将两个集合中中,对应的元素绑定到一起,形成一个元组

最终得到一个新的集合,这个新的集合的元素都是元组

如果两个集合的长度不一样,向短的对齐

val array1=Array[String]("leetom","tom","jerry")
val array2=Array[String]("李tom","汤姆","杰瑞","lee")
//拉链
val res0:Array[(String,String)]=array1.zip(array2)
//解拉链
val unzip:(Array[String],Array[String])=res0.unzip


zipAll:可以将两个集合进行拉链操作
如果集合长度不一致
array1短 thisels填充
array2短 thatels填充
val res1:Array[(String,String)]=array1.zipAll(array2,"array1","arryy2")

元组的遍历

val tuple:(Int,String,Double,Booolean) = (1,"hello",3.14,false)
val iterator:Iterator[Any]=tuple.productIterator
tuple.productIterator.foreach(println(_))
tuple.productIterator.foreach(println)
for (elem<-tuple.productIterator){
    println(elem)
}

Map集合基础使用

val map1:Map[String,String]=Map[String,String]("key1"->"value1","key2"->"value2","key3"->"value3")

获取map中的元素

map1("key1")
不推荐使用,因为这个键如果不存在,则会有异常出现
if(map1.contains("cp")) map1("cp") else "default"

get方法

val res1:Option[String]=map1.get("cp")
返回值是一个Option类型,如果不存在指定的键,直接去get,仍然会发生异常

getOrElse

推荐使用,返回的是cp的value,如果cp不存在,则返回默认值
val res2=map1.getOrElse("cp","default")

集合map的遍历

通过keyset获取到所有的key

val keySet:Set[String]  = map.keySet
for(k<-keySet){
    println(s"key=$k,value=${map(k)}")
}

直接遍历Map,kv的类型是元组

for(kv<-map){
    println(s"key=${kv._1},value=${kv._2})
}

直接遍历map

for((k,v)<-map){
    println(s"key=${k},value=$v")
}

Map集合的操作

元素的crud

map("key1")="valuew"//修改操作
map("key7")="value7"//添加操作
map.update("key1","mc")//更新
map+=("key8"->"wood")//添加
map+=("key9"->"k9","key10"->"k10")
//从另一个集合中添加键值对
map++=map
//删除键值对
map-="key1"
map-=("key2","key3")
//删除一个集合中的所有的键
map--=Array("key4","key5")

List集合

创建一个List集合
val list:List[Int]=Nil//Nil表示一个空集合,没有任何元素
//创建一个空集合
val list2:List[Int]=List()
创建一个有元素的集合
val list3:List[Int]=List(1,2,3,4,5)
val list4:List[List[Int]]=List(List(1,2,3),List(4,5,6),List(7,8,9))
//利用中缀运算符进行创建
//::中缀运算符将多个元素拼接到一起,形成一个List集合
//使用中缀运算符拼接起来的集合必须以Nil结尾
val list5:List[Int]=1::2::3::4::5::Nil //相当于List(1,2,3,4,5)
//中缀运算符是右结合的
val list6:List[Int]=1::(2::(3::(4::(5::Nil))))
val list7:List[List[Int]]=(1::2::3::Nil)::(4::5::6::Nil)::(7::8::9::Nil)
val list8:List[Int]=10::20::list5
val list9:List[Any]=10::20::list5::Nil
//List的遍历
//下标遍历
for(i<-List8.indices){
    println(list8(i))
}
//增强for
for(ele<-list8){
    println()
}
//foreach
list8.foreach(println)

List crud

//List集合是immutable包下的集合,不可变
//有返回值的都是修改后的集合
val list:List[Int]=List(1,2,3,4,5)
val list1:List[Int]=List(6,7,8,9,0)

//向list前方插入数据
val res0:List[Int]=0::list
val res1:List[Int]=list.::(0)
val res2:List[Int]=0+:list
val res3:List[Int]=list.+:(0)

//向list后方追加数据
val res4:List[Int]=list :+ 0

//拼接两个集合
val res5:List[Int]=list++list2
list ::: list2
list2.:::(list)
list ++: list2

List的简便方法

head			获取集合中的首元素
tail			获取集合中除了首元素的其他元素
last			获取集合中的尾元素
init			获取集合中除了last之外的其他元素
isEmpty			判断集合是否为空
take			获取集合中前往后指定元素的数量
takeRight		获取集合中从后往前指定元素的数量
takeWhile		获取集合中满足条件的元素(从前往后查询遇到第一个不满足的元素结束
reverse			集合反转
drop			从前完后删除指定数量的元素
dropRight		从后往前删除指定数量的元素
dropWhile		删除集合中满足条件的元素(从前往后删,遇到第一个不满足条件的元素结束)
splitAt			将一个集合从指定的下标位置开始进行切分操作,切分成两个集合

List集合的模式拆分

val list:List[Int] = List(1,2,3,4)
//依次获取到集合中的每一元素,依次给不同的变量进行赋值
//接收数据的变量的个数,要求与集合中的元素的数量保持一致,否则会出现异常
val List(a,b,c,d)=list

//将集合list中的前两个元素依次赋值给a和b
//集合的其他元素赋值给rest
val a1::b1::rest=list

List集合的高阶方法

foreach(f:Int=>U)
依次将集合中的每一个元素带入到这个参数中进行处理
map(f:Int=>B)
依次返回集合中的每一个元素,带入到这个参数的函数中进行处理
将函数的返回值,作为映射的元素,存到一个新的集合中
最后将这个新的集合返回 
flatMap(f:Int=>GenTraversableOnce[B])
将映射之后的子集合中的数据,存入到一个集合中
参数函数的实现部分,需要将参数转成一个集合
reduce()
将集合中的参数按照相同的逻辑进行处理
fold()
类似reduce也是建所有的元素按照相同的逻辑进行处理
但是和reduce不同的是,fold是可以设置初始值的
filter()
条件过滤可以将集合中的元素,按照指定的规则进行过滤,得到满足条件的元素
sapn
依次遍历集合中每一个元素,判断是否满足指定的条件
找到第一个不满足条件的元素,将之前的元素和从这个元素开始之后的元素分为两个集合
find
查找集合中第一个满足指定条件的元素
partition
分区,这里只支持两个分区
list.foreach(x=>println(x*x))
list.map(x=>x*2)
list.flatMap(x=>x.toList)
list.reduce((x,y)=>x+y)
list.fold(10)(_+_)
list.filter(_%2==1)
list.span(_<5)
list.find(x=>x%2==0)
list.partition(_%2==0)

List集合fora

ll等

forall对集合中的元素条件进行过滤,只有当所有的元素都满足要求时参会返回true否则false
list.forall(_<4)

集合的并行测试
(0 to 10000).map{case _ => Thread.currentThread.getName}.distinct
(0 to 10000).par.map{case_=> Thread.currentThread.getName}.distinct

java和scala的互操作
scala中的集合和java中的集合互相转换需要引入一个包
import scala.collection.JavaConverters._
val list:java.util.List[Int]=List(1,2,3,4,5,6).asJava
val buffer:mutable.Buffer[Int] = list.asScala

Set集合

创建一个set集合
val set1:Set[Int]=Set(1,2,3,1)

添加元素
val res0:Set[Int]=set1+2

从另一个集合中添加元素
val res1:Set[Int]=set1++Set(3,4,5)

添加元素
set+=4
set+=(5,6,7)
set++=Set(8,9,0)

删除元素
set-=3
set-=(4,5,6)
set-=Array(1,2,3)

set.add(10)
set.remove(5)

交集
val set1=Set(1,2,3,4,5)
val set2=Set(3,4,5,6,7)

val res0=set1.instersect(set2)
val res1=set1 & set2
val res2=set1.&(set2)

并集
val res3=set1.union(res2)
val res4=set1 | set2
val res5=set1.|(set2)

差集
val res6=set1.diff(set2)
val res7=set1 &~ set2
val res8=set1.&~(set2)

getter和setter方法

java风格
def setName(name:String):Unit={
    this.name=name
}
def getName:String={
    this.name
}

scala风格属性设计,字段应该以_开头
private var _age: Int= _
def age:Int=_age
def age_=(age:Int):Unit = this._age=age

javaBean规范的,自动提供getter和setter方法
@BeanProperty var gender:String = _

scala中属性必须要给一个初始值,可以与用_来赋值

表示赋值为这种数据类型的默认值

构造器

其实就是构造方法,在scala中会称为构造器,

在scala中列的构造器分两种,主构造器,和辅助构造器

辅助构造器

​ -在类中定义的def this()都是辅助构造器

​ -在辅助构造器中,必须先调用主构造器或者其他构造器

主构造器

​ -类的定义体,就是一个主构造器

主构造器参数描述
n:String会生成私有的字段,不提供setter/getter方法
var/val n:String会生成私有字段,并提setter/getter方法
private var/val n:String会生成私有的子弹并提供私有权限的setter/getter方法
@BeanProperty var/val n:String会生成私有字段,并提供scala和java版本的setter/getter方法

在scala中没有静态的概念,如果要实现静态的功能,使用object单例对象

可以认为:在object中定义的所有成员都是静态的

单例对象主构造器中的逻辑只会执行一次,类似静态代码段

private[this]:

​ 1private:表示一个私有的权限,在类外是不能访问的

​ 2[this]:表示在当前类中,只有哦this可以访问这个属性

有apply方法可以不用new关键字创建对象,只需要识别上参数类型和个数,会自动创建实际上apply在内部也是通过new实现的

unapply提取器

会把对象中对应的属性的值提取出来,可以赋值给元组

伴生对象

在太浓给一个文件中,同时存在一个类和一个单例对象,且名字是相同的

这个对象就是这个类的伴生对象

scala中没有静态的概念,

可以包类中的静态成员写到这个伴生对象中

伴生对象可以访问类中的私有成员

class Leetom{ private var name:String= _}
object Leetom{
def showLeetom(leetom:Leetom):Unit={
    println(leetom.name)
}
}

scala继承和java一样

但是重写要使用override关键字

在scala中只有主构造器可以访问父类中的构造器

子类在定义书信的时候不能var父类的成员因为名字相同如果子再var则会生成新的属性和setter和getter对父类的属性和方法覆盖

向上转型,向下转型

class Leetom{}
calss Lee extends Leetom{}
向上转型
val leetom:Leetom=new Lee

向下转型
if(leetom.isInstanceOf[Lee])
	val lee:Lee = leetom.asInstanceOf[Lee]

抽象类

使用关键字abstract
在scala中如果一个属性定义完成没有初始值
那么这个属性是抽象的,子类就必须覆盖
scala中没有抽象方法可以使用abstract,也可以不使用
如果一个方法么有方法体,只有声明部分,这个方法默认就是抽象方法
def fly():Unit

trait特质

与Java中的接口类似

特质中可以写什么

​ 属性

​ 抽象方法

​ 非抽象方法

实现特质

​ 静态混入

​ 写一个类继承一个特质

​ 一个类继承父类同时继承多个特质

​ 一个类同时继承多个特质

​ class 类名 extends 父类名 with 特质1 with 特质2 with 特质3

​ 动态混入

​ 可以在实例化一个对象的同时混入一个特质

​ 此时这个类可能并没有继承到这个特质,其他的对象是没有特质中的成员

​ 只针对这一个对象生效

一个类在继承了父类的特质的时候,可以继承到所有父类和特质中的所有成员

在scala中定义枚举,需要设计一个单例对象object继承自枚举的助手类Enumeration,在枚举中需要定义value类型的成员作为枚举的值

可以不设置id和name如果不设置id一个value的id是从上一个id值子增1 ,最开始的value是从0开始id,如果不设置name一个value的name就是前面的变量的值

object Weekday extends Enumeration{
    val MONDAY:Weekday.Value=Value(1,"星期一")
    val TUESDAY:Weekday.Value=Value
}

使用枚举
val monday:Weekday.Value=Weekday.MONDYAY
val thuday:Weekday.Value=Weekday(4)
val friday:Weekday.Value=Weekday.withName("星期一")

遍历枚举
val values:Weekday.ValueSet=Weekday.values
for(value<-values){
    println(s"id=${value.id},name=$value")
}

样例类

使用case class定义的类就是一个样例类
样例类的名字后面必须要添加参数列表,即便不需要形参,也必须把下括号加上
样例类的主构造器中的参数
	如果没写var/val只写了参数的名字和类型
	此时会生成属性,但是默认是val提供了getter方法
	如果写了var
	会生成属性提供了setter和getter方法
样例类会自动重写tostring,equals,hashcode,clone
样例类会自动的添加apply和unapply方法

模式匹配

值匹配

模式匹配中没有穿透性

在case后,多个值可以使用|拼接到一起表示或

使用_表示上述的case都不成立的情况

可以在case后面添加if守卫

如果变量的值没有在case中找到匹配项,会出现异常

val season=StdIn.readline("输入一个季节数字")
season match{
    case "1"=>println("春天")
    case "2"=>println("夏天")
    case "3"=>println("秋天")
    case "4"=>println("冬天")
    case _=>println("其他")
}

类型匹配

匹配的是变量的实际类型,而不是向上转型后的类型

在case后面可以使用一个变量,在存储匹配的变量的值,这个过程中会向下转型

如果不需要做向下转型,可以直接在case后面写类型,或者写_:类型

class Animal
class Dog extends Aniaml
class Cat extends Aniaml

向上转型
val animal:Animal=new Dog

向下转型
animal match{
	case dog:Dog=>pringln
	......
}

集合元素匹配

数组匹配
val array=Array(1,2,3)
array match{
    case Array(1)=>println(...)
    case Array(a,b)=>println(...)
    case Array(1,_*)=>
    case _=>
}

列表匹配
val list=List(1,2,3)
list match{
    case List(1)=>
    case List(a,b)=>
    case List(1,_*)=>
    case _=>
}

元组匹配
val tuple=(3.14,10)
tuple match{
    case(3.14,100)=>
    case(a,10)=>
    case _=>
}

对象的匹配

可以匹配到对象的属性,给指定的变量进行赋值
需要依赖nuapply方法
case calss Student(var name:String,var age:Int,var score:Int)
val student=new Student("leetom",18,99)
student match{
	case Student("leeotm",18,99)=>
	case Student("Leetom",age,score)=>
	case Student(n,a,s)=>
	case student(n,a,_)=>
	case _ =>
}

option类型

代表可选,用来表示可能存在,也可能不存在的值
option有两个类型分别是some和none

val map=Map("leetom"->"jerry")
val maybeString:Option[String]=map.get("lee")
maybeString match{
    case Some(x)=>
    case None=>
}

高阶函数:当一个函数的参数或者返回值为其他函数,这样的函数就是高阶函数

def calcualte(f:(Int,Int)=>Int,Int,Int)=>Int=_(_,_)
calculator2(_+_,100,200)

函数作为返回值

定义一个高阶函数:返回值作为其他的函数
val calculator1:Boolean=>(Int,Int)=>Int=x=>{
    if(x)
    	_+_
    else
    	_+_
}

闭包

如果一个函数中使用到函数之外的局部变量,并且在函数体或者返回值中需要依赖这个变量,此时就形成了一种现象,这个函数体将这个局部变量包围起来了,这种现象就是闭包,如果形成了闭包,函数就会提升包围这个局部变量的声明周期

var number=10
val function1:Int=>Int={
    _*number
}

柯里化

非柯里化
def leetom(x:Int,y:Int):Int={
    x+y
}
柯里化
def curringCalculate(x:Int)(y:Int):Int={
    x+y
}

偏函数

偏函数是一种模式匹配
偏函数是partialfunction的实例,自定义的偏函数需要以partialfunction为返回值,在partialfunction特质中,有两个泛型,第一个是输入类型,第二个是输出类型使用partialfunction的时候常用方法
apply=>应用偏函数中的逻辑,也就是为执行自定义的偏函数中的逻辑
isdefinedat=>检测偏函数逻辑中,是否有指定的匹配项
apply方法的调用,可以省略apply
def f1:PartialFunction[Int,String]={
    case 1=>"一"
    case _=>"其他"
}

val f:PartialFunction[Int,String]=f1
val res:String=f.apply(1)
println(res)
println(f.isDefineAt(1))
println(f(1))

隐式类

作为一个类的功能拓展
隐式类,需要关键字implict修饰,是对某一个类进行功能的拓展
隐式类的
objcet ImplictClasses{
    implict class StringExtension(str:String){
        def show():Unit={
            println(str+"~")
        }
        def getArray(sep:String=", "):Array[String]={
            str.split(sep)
        }
    }
}
val array1:Array[String]="leetom,lee,le,ll".getArray()
val array2:Array[String]="List---Lcs--Lsdf-fd-ll".getArray("-+")

隐式方法

主要用来做类型之间的隐式转换

1隐式方法的定义需要使用关键字implict
2.同一上下文中,不能出现两个同样类型的参数和返回值隐式方法
object ImpicFuntions{
    implict def string2Int(str:String):Int=Integer.parseInt(str)
}
val number:Int="1234"

隐式参数

在方法或者函数的参数列表中,使用implict修饰的参数,就是隐式参数
implict只能放在参数的最前方,修饰的是整个参数列表
有隐式参数的方法,调用的时候正常传参
在调用的时候,如果当前上下文中有隐式参数,则直接将这个隐式变量作为方法隐式参数的实参
同一个上下文中不能出现两个相同类型的隐式参数
对集合的扩展
ordering就是scala的comparator
ordered就是scala的comparable
def calculate(implicit x:Int):Int=x*x
def calculate1(x:Int)(implicit y:Int):Int=x+y
隐式变量
implicit val number:Int=10
implicit val n:String="100"
//在调用有隐式参数的方法的时候,如果当前上下文有隐式变量,则直接将这个隐式变量作为方法的隐式参数的实参

泛型

使用类的时候直接指定泛型的类型,

class Calculate[A]{
    var intstance:A=_
}
class Calcualte2[A](var ele:A){
    var instance:A=_
}
​
var value=new Calculate[Int]()

在使用类的时候可以不指定泛型的类型,通过构造器中的参数进行推导

val value1=new Calculate2(10)

泛型的协变和逆变

协变,如果dog是Animal的子类,则test[dog]是test[animal]的子类型,可以向上转型

逆变,如果dog是haq的父类,则test[dog]是test[haq]的子类型可以向上转型

泛型类协变
class Test1[+A]
逆变
class Test1[-A]
​
class Animal
class Dog extends Animal
class Haq extends Dog
​
协变
val test1:Test1[Animal]=new Test1[Dog]
逆变
val test2:Test2[Haq]=new Test2[Dog]

泛型的上界和下界

泛型的上界:设置一个可以设置泛型的上边界,

使用这个类的时候在使用这个类的时候,泛型的必须设置为指定类或者该类的子类类型

泛型的下界:这是一个可以设置泛型的下边界

使用这个类的时候在是使用这个类,泛型必须设置为指定的类,或者该类的父类

class Animal
class Dog extends Animal
class Haq extends Dog
上界
class Test1[A<:Dog]
下界
class Test2[A>:Dog]
​
val test1=new Test1[Haq]()
val test2=new Test2[Animal]()

视界,类似于上边界

[A%B]

要求A是B的子类型或者可以由A类型隐式转换为B类型

class Animal
class Dog extends Animal
class Haq extends Dog
class Test[A%Dog] 
implicit def str2Dog(str:String):Dog=null
​
val test1 = new Test[String]()

上下文界定

[A:B]

B类型必须是一个泛型类

当前上下文中必须有一个隐式类的B类型的变量

这个隐式变量的类型要求是B[A]

class Test[A]
class Test1[A:Test]
​
implicit val test:Test[Int] = new Test[Int]
val value=new Test1[Int]

字符串插值

s""=>插入变量

f""=>表示可以进行格式化

raw""=>字符串中的特殊字符,不用做转义,但是仍然不能做转义

println(s"大家好,我叫$name, 我今年${age}岁了,我的身高是${height}cm")
        println(f"大家好,我叫$name%-10s, 我今年${age}岁了,我的身高是${height}%.2fcm")
        println(raw"大家好,我叫$name \n 我今年${age}岁了 \n 我的身高是${height}cm")

"""""""三个双引号,可以放引号

val res: String =
            s"""大家好
               |我叫"$name"
               |今年"$age"岁了
               |""".stripMargin
​
        println(res)

正则表达式

正则基础

val regex:String="\\w{4,12}@(126|163|qq|QQ)\\.(com|cn)"
val email:String="leetom@qq.com"
email.matches(regex)

正则查找

查找一个满足字符串中满足正则规则的部分
 // 1. 准备一个字符串
        val str: String = "hello123world456nihao789hi012"
        // 2. 设计正则
        val regex: Regex = "\\d+".r
​
        // 3. 查找第一个匹配项
        val res0: Option[String] = regex.findFirstIn(str)
        res0 match {
            case Some(x) => println(x)
            case None => println("没有找到匹配项")
        }
​
        // 4. 查找每一个匹配项
        val iterator: Regex.MatchIterator = regex.findAllIn(str)
        while (iterator.hasNext) {
            println(iterator.next())
        }

正则替换

// 1. 准备一个字符串
        val str: String = "hello123world456nihao789hi012"
        // 2. 设计正则
        val regex: Regex = "\\d+".r
​
        println(regex.replaceFirstIn(str, "数字部分"))
        println(regex.replaceAllIn(str, "数字部分"))
        println(regex.replaceAllIn(str, matcher => {
            // 指定的匹配
            // matcher: 是一次匹配的结果
            // matcher.matched: 表示本次匹配到的数据
            matcher.matched match {
                case "789" => "数字部分"
                case _ => matcher.matched
            }
        }))

正则提取

val email: String = "shawn@163.com"
        val regex: Regex = "(\\w{4,12})@((126|163|qq|QQ)\\.(com|cn))".r
​
        // 模式匹配
        // case之后,使用regex接收的变量的个数,一定要和正则中的分组的数量是一致的
        email match {
            case regex(user, domain, _, _) =>
                println(s"user = $user, domain = $domain")
            case _ =>
                println("没有找到匹配项")
        }

正则分组

val email: String = "shawn@163.com    luds@126.com    xc001@qq.com   xc002@QQ.cn"
        val regex: Regex = "(\\w{4,12})@((126|163|qq|QQ)\\.(com|cn))".r
​
        // 获取到一个字符串中所有的匹配项
        val matches: Iterator[Regex.Match] = regex.findAllMatchIn(email)
​
        // 遍历所有的匹配项
        for (matcher <- matches) {
            // 1. 获取有多少个分组
            val count: Int = matcher.groupCount
​
            // 2. 遍历每一个分组
            for (i <- 1 to count) {
                println(s"第${i}组的内容是: ${matcher.group(i)}")
            }
            println("====================")
        }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值