Scala代码编译成字节码,交给JVM执行
一、apply函数
在object中定义apply函数,使用"类名()"的形式,其实就是"类名.apply()"的一种缩写。
通常使用这种方式来构造类的对象,而不是使用"new 类名()"的方式。
二、if表达式是有值的,最后一行语句返回的值
val isAdult = if (age > 18) 1 else 0
如果if和else子句的值类型不同,则对两个类型的公共父类型:if(age>18) "adult" else 0 //返回Any
如果if没有else子句,则默认else的值是Unit,也用()表示,类似java中的void或者null。
三、没有形似这种for(;;)循环,可以使用简易版for循环:for(i <- 1 to 10)
1 to 3 => 1 2 3
1 until 3 => 1 2
scala没有提供类似java的break语句。可以使用boolean类型变量、return或者Breaks的break函数来替代使用。
import scala.util.control.Breaks._
breakable{
var n = 10
for(c <- "Hello World"){
if(n==5) break;
n -= 1
}
}
多重for循环:for(i <- 1 to 9 ; j <- 1 to 9)
if守卫: for(i <- 1 to 100 if i%2==0) println(i) //取偶数
for推导式:构造集合 for(i <- 1 to 10) yield i
四、函数
1、变长参数:def sum(n:Int*) = {},如果想传入一个序列,sum(1 to 5)是错误的,正确写法是:sum(1 to 5: _*)
函数后面有=,说明有返回值,如果没有显式写明返回值类型,系统会自动推导返回值类型;如果没有=,则说明没有返回值
2、过程:没有返回值的函数
def f(name:String){}
def f(name:String):Unit={}
3、lazy:第一次使用才会执行计算 lazy val lines=...
4、异常
try{
}catch{
case _:
}finally{
}
五、数组
val a = new Array[Int](10) 访问元素是用(),如a(0),不是[]
或者val a = Array("hello","world")
可变长度:val b = ArrayBuffer[Int]()
b+=1 //加一个元素
b+=(2,3,4,5) //加多个元素
b++=Array(6,7,8,9) //添加其他集合的所有元素
b.trimEnd(5) //从尾部截断指定个数的元素
遍历数组:
for(i <- 0 until b.length) println(b(i)) //顺序遍历
for(i <- 0 until (b.length,2)) println(b(i)) //隔一个遍历
for(i <- (0 until b.length).reverse) println(b(i)) //从尾部遍历
for(e <- b) println(e)
数组转换:
val a = Array(2,3,5,7,11)
val result = for (elem <- a) yield 2 * elem
for ( elem <- a if elem % 2 == 0) yield 2 * elem
val result = a.map(_ * 2)
val result2 = a.filter(_ % 2 == 0)
六、Map
可变: val ages = Map("leo"->1,"xm"->2)
不可变:val ages = scala.collection.mutable.Map("leo"->1,"xm"->2)
val ages = Map(("leo",1),("xm",2))
添加元素 ages+=("zz"->3)
移除元素 ages-="zz"
遍历:for((key,value)<-ages) println(key+" "+value)
for(key<-ages.keys) println(key+" ")
for(value<-ages.values)
排序:scala.collection.immutable.SortedMap(ages) //对key进行排序
七、Tuple
定义元组:val t = (1, 3.14, "Fred")
访问元素:t._1
八、getter和setter方法
类里面定义的是 方法 ,类外面定义的是 函数
在类里面定义方法时,如果不带括号,如 def getName = name,则在调用时不能带括号:对象名.getName
如果定义方法带括号,但没有参数,则调用时带不带括号都行
1、getter和setter方法
(1)定义不带private的var field,自动生成提供public的getter和setter方法;如果使用private修饰,则生成
的getter和setter也是private的;如果定义val field,则只会生成getter方法;如果field声明为 private[this]
则不生成getter和setter方法,并且该field不能被其他对象访问,只能在本对象内可以访问
class Student{
var name = "leo"
}
val s = new Student //定义对象
s.name //调用getter方法
s.name="zz" //调用setter方法
(2)自定义getter和setter方法
class Student{
private var myAge=0
def age_=(newValue:Int){ //setter方法,注意:age_= 之间不能有空格
if(newValue>0) myAge=newValue
else println("illegal age!")
}
def age = myAge //getter方法
}
val s = new Student
s.age=10 //调用setter方法,myAge的值发生改变
s.age //调用getter方法
九、构造函数
(1)主构造函数:与类名放在一起,在类中,没有定义在方法中或者代码块中的代码,就是主构造函数的代码
class Student(val name:String="leo",val age:Int=30){
println(name+" "+age)
}
如果参数没有任何修饰,比如name:String,当内部中使用到该参数,则自动声明为private[this] name,否则
没有该参数,仅仅是被主构造函数的代码使用而已,这是一个优化机制。
(2)辅助构造函数:this
class Student{
private var name=""
private var age=0
def this(name:String){ //辅助构造函数
this() //第一行必须调用主构造函数,这个类的主构造函数没有参数
this.name=name
}
def this(name:String,age:Int){ //辅助构造函数
this(name)
this.age=age
}
}
十、object
1、相当于class的单个实例,通常在里面放一些静态的field或者method;
第一次调用object方法时,就会执行object的构造方法(仅执行一次),也就是不在方法内部的代码,但object构造方法不能接受参数;
2、继承抽象类
十一、继承 extends
1、用final修饰的field和method,则是无法继承
override 覆盖field或者method
super 调用父类的field或者method
2、isInstanceOf:判断对象是否为指定类的对象,如:p.isInstanceOf[Student],如果p是null,则返回false
asInstanceOf:将对象转换为指定类型,如p.asInstanceOf[Student],如果p是null,则返回null
如果没有用isInstanceOf先判断,就直接用asInsatanceOf转换,则可能会抛出异常
注意:isinstanceOf只能判断出对象是否是指定类以及其子类对象,而不能精确判断出对象就是指定类的对象
3、getClass和clssOf
对象.getClass 可以精确获取对象的类,classOf[类] 可以精确获取类,然后使用==操作符判断,如 p.getClass==classOf[Student]
4、使用模式匹配进行类型判断,这和isInstanceOf一样的,不能精确判断出类的对象
十二、protect
有private修饰的field或者method,子类可以通过 super.field 访问父类的field或者method,
有protect修饰的field或者method,子类可以直接访问父类的field或者method,如果是protect[this],则只能在当前实例中访问,其他实例不能访问
十三、调用父类的构造函数
在extends 父类时,就将参数传给父类,如:class Person(val name:String) class Student(name:String,val age:int) extends Person(name)
注意:如果是父类接收的参数,比如name,子类定义时就不要加val或者var修饰,否则会认为是子类覆盖父类的field
十四、Trait
1、作为接口使用,使用extends和with继承多个trait,实现trati方法时,不需要使用override,也可以使用override
2、定义具体方法,通常是工具方法
3、定义具体field,混入trait时,直接添加到类中;与继承父类不一样
4、定义抽象field
5、为实例动态混入trait 如:val p = new Person("jack") with Log
6、trait调用链
继承多个trait,并且多个trait中有同一个方法(比如handle()),在该同一个方法的最后都执行 super.handle ,则在类中调用handle方法时,
会首先调用最右边trait的handle方法,然后依次向左,形成一个调用链条
7、覆盖抽象方法
覆盖时,如果使用了 super.方法 ,则需要给该方法加上 abstract override修饰,因为super是调用父trait抽象方法,此时子trait该方法还是会被认为是抽象的
8、构造方法没有参数
9、可以继承class
十五、函数
1、将函数赋值给变量 : val p = sayHello _ //将函数赋值给变量时,函数名后面是 空格+下划线
2、匿名函数: (参数名:参数类型)=> 函数体
3、高阶函数:将函数作为参数传入到另一个函数中,函数的返回值是一个函数
4、常用高阶函数:map foreach filter reduce reduceLeft sortWith zip
5、闭包
十六、集合操作
1、List ::操作符 0::list 表示将0和list拼接起来
Nil 表示空
2、LinkedList 可变列表 scala.collection.mutable.LinkedList
十七、模式匹配
case class Teacher(name:String,subject:String)
grade match {
case "A" => 处理语句
case "B" if name=="leo" => 处理语句 //在case后加条件判断
case e1:IOException => 处理语句 //对类型进行模式匹配
case badGrade => 处理语句 //将默认情况(下划线),替换为一个变量名(badGrade),在不满足上面情况下,会将值赋给badGrade,然后在处理语句中使用
case Array("Leo") => 处理语句 //对只有一个元素的Array进行匹配
case Array(a1,a2,a3) => 处理语句 //对有3个元素的Array进行匹配
case Array("Leo",_*) => 处理语句 //对第一个元素是"Leo"的Array进行匹配
case "Leo"::Nil => 处理语句 //对只有一个元素的List进行匹配
case a1,a2,a3::Nil => 处理语句 //对有3个元素的List进行匹配
case "Leo"::tail => 处理语句 //对第一个元素是"Leo"的List进行匹配
case Teacher(name,subject) => 处理语句 //对case class进行匹配
case Some(grade) => 处理语句 //对Option进行匹配,有值
case None => 处理语句 //对Option进行匹配,无值
case _ => 处理语句 //默认情况
}
十八、类型参数
1、泛型类:
class Student[T](val id:T){}
2、泛型函数:
def getCard[T](content:T)={}
3、上边界Bounds:
class Person(val name:String)
class Party[T <: Person](p1:T,p2:T) //T必须是Person或者其子类
4、下边界Bounds:
def getIDCard[T >: Child](p:T) //T必须是Child或者其父类
5、View Bounds:是上下边界的加强版,支持类型隐式转换,进行类型转换后,再对类型进行边界指定
implicit def dog2person(obj:Object):Person = if(obj.isInstanceOf[Dog]){ val dog=obj.asInstanceOf[Dog];new Person(dog.name)} else Nil
class Party[T <% Person](p1:T,p2:T)
6、Context Bounds:是一种特殊的Bounds,它会根据泛型类型的声明,比如"T:类型",要求必须存在一个类型为"类型[T]"的隐式值。
class Calculator[T:Ordering](val n1:T,val n2:T){
def max(implicit order:Ordering[T]) = if(order.compare(n1,n2)>0) n1 else n2
}
7、Manifest Context Bounds:在scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T,需要为类
或者函数定义[T:Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组。
def packageFood[T:Manifest](food:T*)={
val foodPackage=new Array[T](food.length)
for(i <- 0 until food.length) foodPackage(i)=food(i)
foodPackage
}
8、协变和逆变
class Master
class Profession extends Master
(1)class Card[+T](val name:String) => Card[Master]是Card[Profession]的父类 协变
(2)class Card[T](val name:String) => Card[Master]与Card[Profession]没有关系
(3)class Card[-T](val name:String) => Card[Master]是Card[Profession]的子类 逆变
9、Existential Type:存在性类型,比如 Array[_]中的 _ 表示一种类型
十九、actor
1、scala的多线程编程,重启Actor trait的act方法,实现线程执行体,与java重写run方法类似,使用start()方法启动actor,
使用符号!向actor发送消息,使用receive和模式匹配接收消息
import scala.actors.Actor
class HelloActor extends Actor{
def act(){
while(true){
receive{
case name:String => println("Hello,"+name)
}
}
}
}
val helloActor= new HelloActor
helloActor.start() //启动actor
helloActor ! "leo" //发送消息
2、默认情况下,消息都是异步的,如果希望是同步的,即对方接受消息后,一定要给自己返回结果,使用 !? 发送消息,如val r=actor !? message
3、发送异步消息,不需要马上返回消息,在需要用到返回消息的地方才获取返回消息,用 !! ,如 val future = actor !! message
val reply = future()
二十、跳出循环的方法
1、通过标志 如 while(flag)
2、通过return
3、使用Breaks对象的break方法,与breakable代码块配合使用
如import scala.util.control.Breaks._
breakable{
break
}
二十一、多维数组
1、构造指定行与列的二维数组: val a = Array.ofDim[Double](3,4)
2、构造不规则多维数组
val ma = new Array[Array[Int]](3)
ma(0) = new Array[int](2)
3、java数组与scala数组的隐式转换
scala代码中,直接调用JDK(java)的API,比如调用一个java类的方法,需要传入java中的list,scala构造出来的list其实是ArrayBuffer,需要进行转换
import scala.collection.javaConversions.bufferAsJavaList //ArrayBuffer隐式转换为java list
import scala.collection.javaConversions.asScalaBuffer //java list 隐式转换为ArrayBuffer
二十二、
1、Tuple拉链操作:zip操作 a1=Array(v1) a2=Array(v2) a3=a1.zip(a2) => Array((v1.v2))
for((v1,v2) <- a3) a3.toMap
2、Java Map 与 Scala Map的隐式转换
import scala.collection.JavaConversions.mapAsScalaMap //Java Map隐式转换为Scala Map
import scala.collection.JavaConversions.mapAsJavaMap //Scala Map隐式转换为Java Map
3、内部类
(1)如果一个内部类定义在外部类里,则这个内部类是属于该外部类对象的
(2)如果一个内部类定义在伴生对象中,则这个内部类是属于该外部类的
(3)如果一个内部需要获取外部类对象,则
class A(val n:String){ outer=>
class B(val z:String){
//outer代表外部类对象
}
}
4、重写field的定义
默认情况下,如果父类中的构造函数代码,用到了会被子类重写的field,则会出现:
(1)子类构造函数调用父类的构造函数
(2)父类的构造函数初始化field(结果正确)
(3)父类构造函数执行其他构造代码,如果其他构造代码使用了该field,而且该field要被子类重写,则该field的getter方法被重写,返回0
(4)子类的构造函数执行,重写field
(5)从父类继承的其他构造代码,已经出现了错误
class Student{
val classNumber:Int=10
val classScores:Array[Int]=new Array[Int](classNumber)
}
class PEStudent extends Student{
val classNumber:int=3
}
val a = new PEStudent // a的classScores的长度只有0,而期望的长度是3
为了解决上述问题,要使用scala的一个高级特性:提前定义,在父类构造函数执行之前,先执行子类的构造函数中的某些代码
class PEStudent extends Student{
val classNumber:int=3 //该构造代码 比 父类构造函数代码 先执行
} with Student
二十三、文件操作
1、import scala.io.Source
val s = Source.fromFile("filePath","UTF-8")
val lineIterator = s.getLines //返回迭代器
for(line <- lineIterator) println(line)
val lines = s.getLines.toArray //返回数组
for(line <- lines) println(line)
val lines = s.mkString //返回文本中所有内容
for(c <- s) print(c) //遍历文件中每一个字符
val html=Source.fromURL("xxx","UTF-8") //从URL读取字符
val str=Source.fromString("Hello World") //从字符串读取字符
2、结合java IO流
二十四、偏函数
是一种高级的函数形式,其实就是没有定义好明确的输入参数的函数,函数体是一连串的case语句
偏函数是PartialFunction[A,B]类的一个实例,这个类有两个方法,apply()方法,直接调用可以通过函数体内的case进行匹配,返回结果;
另一个是isDefinedAt()方法,返回一个输入是否跟任何一个case语句匹配
val getStudentGrade:PartialFunction[String,Int] = {
case "Leo" => 90; case "Jack" => 85; case "Marry" => 95
}
getStudentGrade("Leo")
getStudentGrade.isDefinedAt("Tom")
二十五、执行外部命令
import sys.process._
"ls -ltr" ! // 使用 ! 来表示执行字符串的外部命令
二十六、正则表达
定义正则表达式: val pattern = "[a-z]+".r
val str = "hello 123 world 456"
for(matchStr <- pattern.findAllIn(str)) println(matchStr)
for(matchStr <- pattern.findFirstIn(str)) println(matchStr)
pattern.replaceAllIn(str,"zzz")
pattern.replaceFirstIn(str,"xxx")
二十七、提取器
就是定义一个包含unapply方法的对象,跟apply方法相关,apply方法是接收参数,构造出一个对象,
unapply方法是接收一个字符串,解析出对象的属性值
class Person(val name:String,val age:Int)
object Person{
def apply(name:String,age:Int) = new Person(name,age)
def unapply(str:String){
val splitIndex = str.indexOf(" ")
if(splitIndex==-1) None
else some((str.substring(0,splitIndex),str.substring(splitIndex+1)))
}
}
val Person(name,age)="leo 25" //调用提取器,变量name的值"leo",age的值为25
一、apply函数
在object中定义apply函数,使用"类名()"的形式,其实就是"类名.apply()"的一种缩写。
通常使用这种方式来构造类的对象,而不是使用"new 类名()"的方式。
二、if表达式是有值的,最后一行语句返回的值
val isAdult = if (age > 18) 1 else 0
如果if和else子句的值类型不同,则对两个类型的公共父类型:if(age>18) "adult" else 0 //返回Any
如果if没有else子句,则默认else的值是Unit,也用()表示,类似java中的void或者null。
三、没有形似这种for(;;)循环,可以使用简易版for循环:for(i <- 1 to 10)
1 to 3 => 1 2 3
1 until 3 => 1 2
scala没有提供类似java的break语句。可以使用boolean类型变量、return或者Breaks的break函数来替代使用。
import scala.util.control.Breaks._
breakable{
var n = 10
for(c <- "Hello World"){
if(n==5) break;
n -= 1
}
}
多重for循环:for(i <- 1 to 9 ; j <- 1 to 9)
if守卫: for(i <- 1 to 100 if i%2==0) println(i) //取偶数
for推导式:构造集合 for(i <- 1 to 10) yield i
四、函数
1、变长参数:def sum(n:Int*) = {},如果想传入一个序列,sum(1 to 5)是错误的,正确写法是:sum(1 to 5: _*)
函数后面有=,说明有返回值,如果没有显式写明返回值类型,系统会自动推导返回值类型;如果没有=,则说明没有返回值
2、过程:没有返回值的函数
def f(name:String){}
def f(name:String):Unit={}
3、lazy:第一次使用才会执行计算 lazy val lines=...
4、异常
try{
}catch{
case _:
}finally{
}
五、数组
val a = new Array[Int](10) 访问元素是用(),如a(0),不是[]
或者val a = Array("hello","world")
可变长度:val b = ArrayBuffer[Int]()
b+=1 //加一个元素
b+=(2,3,4,5) //加多个元素
b++=Array(6,7,8,9) //添加其他集合的所有元素
b.trimEnd(5) //从尾部截断指定个数的元素
遍历数组:
for(i <- 0 until b.length) println(b(i)) //顺序遍历
for(i <- 0 until (b.length,2)) println(b(i)) //隔一个遍历
for(i <- (0 until b.length).reverse) println(b(i)) //从尾部遍历
for(e <- b) println(e)
数组转换:
val a = Array(2,3,5,7,11)
val result = for (elem <- a) yield 2 * elem
for ( elem <- a if elem % 2 == 0) yield 2 * elem
val result = a.map(_ * 2)
val result2 = a.filter(_ % 2 == 0)
六、Map
可变: val ages = Map("leo"->1,"xm"->2)
不可变:val ages = scala.collection.mutable.Map("leo"->1,"xm"->2)
val ages = Map(("leo",1),("xm",2))
添加元素 ages+=("zz"->3)
移除元素 ages-="zz"
遍历:for((key,value)<-ages) println(key+" "+value)
for(key<-ages.keys) println(key+" ")
for(value<-ages.values)
排序:scala.collection.immutable.SortedMap(ages) //对key进行排序
七、Tuple
定义元组:val t = (1, 3.14, "Fred")
访问元素:t._1
八、getter和setter方法
类里面定义的是 方法 ,类外面定义的是 函数
在类里面定义方法时,如果不带括号,如 def getName = name,则在调用时不能带括号:对象名.getName
如果定义方法带括号,但没有参数,则调用时带不带括号都行
1、getter和setter方法
(1)定义不带private的var field,自动生成提供public的getter和setter方法;如果使用private修饰,则生成
的getter和setter也是private的;如果定义val field,则只会生成getter方法;如果field声明为 private[this]
则不生成getter和setter方法,并且该field不能被其他对象访问,只能在本对象内可以访问
class Student{
var name = "leo"
}
val s = new Student //定义对象
s.name //调用getter方法
s.name="zz" //调用setter方法
(2)自定义getter和setter方法
class Student{
private var myAge=0
def age_=(newValue:Int){ //setter方法,注意:age_= 之间不能有空格
if(newValue>0) myAge=newValue
else println("illegal age!")
}
def age = myAge //getter方法
}
val s = new Student
s.age=10 //调用setter方法,myAge的值发生改变
s.age //调用getter方法
九、构造函数
(1)主构造函数:与类名放在一起,在类中,没有定义在方法中或者代码块中的代码,就是主构造函数的代码
class Student(val name:String="leo",val age:Int=30){
println(name+" "+age)
}
如果参数没有任何修饰,比如name:String,当内部中使用到该参数,则自动声明为private[this] name,否则
没有该参数,仅仅是被主构造函数的代码使用而已,这是一个优化机制。
(2)辅助构造函数:this
class Student{
private var name=""
private var age=0
def this(name:String){ //辅助构造函数
this() //第一行必须调用主构造函数,这个类的主构造函数没有参数
this.name=name
}
def this(name:String,age:Int){ //辅助构造函数
this(name)
this.age=age
}
}
十、object
1、相当于class的单个实例,通常在里面放一些静态的field或者method;
第一次调用object方法时,就会执行object的构造方法(仅执行一次),也就是不在方法内部的代码,但object构造方法不能接受参数;
2、继承抽象类
十一、继承 extends
1、用final修饰的field和method,则是无法继承
override 覆盖field或者method
super 调用父类的field或者method
2、isInstanceOf:判断对象是否为指定类的对象,如:p.isInstanceOf[Student],如果p是null,则返回false
asInstanceOf:将对象转换为指定类型,如p.asInstanceOf[Student],如果p是null,则返回null
如果没有用isInstanceOf先判断,就直接用asInsatanceOf转换,则可能会抛出异常
注意:isinstanceOf只能判断出对象是否是指定类以及其子类对象,而不能精确判断出对象就是指定类的对象
3、getClass和clssOf
对象.getClass 可以精确获取对象的类,classOf[类] 可以精确获取类,然后使用==操作符判断,如 p.getClass==classOf[Student]
4、使用模式匹配进行类型判断,这和isInstanceOf一样的,不能精确判断出类的对象
十二、protect
有private修饰的field或者method,子类可以通过 super.field 访问父类的field或者method,
有protect修饰的field或者method,子类可以直接访问父类的field或者method,如果是protect[this],则只能在当前实例中访问,其他实例不能访问
十三、调用父类的构造函数
在extends 父类时,就将参数传给父类,如:class Person(val name:String) class Student(name:String,val age:int) extends Person(name)
注意:如果是父类接收的参数,比如name,子类定义时就不要加val或者var修饰,否则会认为是子类覆盖父类的field
十四、Trait
1、作为接口使用,使用extends和with继承多个trait,实现trati方法时,不需要使用override,也可以使用override
2、定义具体方法,通常是工具方法
3、定义具体field,混入trait时,直接添加到类中;与继承父类不一样
4、定义抽象field
5、为实例动态混入trait 如:val p = new Person("jack") with Log
6、trait调用链
继承多个trait,并且多个trait中有同一个方法(比如handle()),在该同一个方法的最后都执行 super.handle ,则在类中调用handle方法时,
会首先调用最右边trait的handle方法,然后依次向左,形成一个调用链条
7、覆盖抽象方法
覆盖时,如果使用了 super.方法 ,则需要给该方法加上 abstract override修饰,因为super是调用父trait抽象方法,此时子trait该方法还是会被认为是抽象的
8、构造方法没有参数
9、可以继承class
十五、函数
1、将函数赋值给变量 : val p = sayHello _ //将函数赋值给变量时,函数名后面是 空格+下划线
2、匿名函数: (参数名:参数类型)=> 函数体
3、高阶函数:将函数作为参数传入到另一个函数中,函数的返回值是一个函数
4、常用高阶函数:map foreach filter reduce reduceLeft sortWith zip
5、闭包
十六、集合操作
1、List ::操作符 0::list 表示将0和list拼接起来
Nil 表示空
2、LinkedList 可变列表 scala.collection.mutable.LinkedList
十七、模式匹配
case class Teacher(name:String,subject:String)
grade match {
case "A" => 处理语句
case "B" if name=="leo" => 处理语句 //在case后加条件判断
case e1:IOException => 处理语句 //对类型进行模式匹配
case badGrade => 处理语句 //将默认情况(下划线),替换为一个变量名(badGrade),在不满足上面情况下,会将值赋给badGrade,然后在处理语句中使用
case Array("Leo") => 处理语句 //对只有一个元素的Array进行匹配
case Array(a1,a2,a3) => 处理语句 //对有3个元素的Array进行匹配
case Array("Leo",_*) => 处理语句 //对第一个元素是"Leo"的Array进行匹配
case "Leo"::Nil => 处理语句 //对只有一个元素的List进行匹配
case a1,a2,a3::Nil => 处理语句 //对有3个元素的List进行匹配
case "Leo"::tail => 处理语句 //对第一个元素是"Leo"的List进行匹配
case Teacher(name,subject) => 处理语句 //对case class进行匹配
case Some(grade) => 处理语句 //对Option进行匹配,有值
case None => 处理语句 //对Option进行匹配,无值
case _ => 处理语句 //默认情况
}
十八、类型参数
1、泛型类:
class Student[T](val id:T){}
2、泛型函数:
def getCard[T](content:T)={}
3、上边界Bounds:
class Person(val name:String)
class Party[T <: Person](p1:T,p2:T) //T必须是Person或者其子类
4、下边界Bounds:
def getIDCard[T >: Child](p:T) //T必须是Child或者其父类
5、View Bounds:是上下边界的加强版,支持类型隐式转换,进行类型转换后,再对类型进行边界指定
implicit def dog2person(obj:Object):Person = if(obj.isInstanceOf[Dog]){ val dog=obj.asInstanceOf[Dog];new Person(dog.name)} else Nil
class Party[T <% Person](p1:T,p2:T)
6、Context Bounds:是一种特殊的Bounds,它会根据泛型类型的声明,比如"T:类型",要求必须存在一个类型为"类型[T]"的隐式值。
class Calculator[T:Ordering](val n1:T,val n2:T){
def max(implicit order:Ordering[T]) = if(order.compare(n1,n2)>0) n1 else n2
}
7、Manifest Context Bounds:在scala中,如果要实例化一个泛型数组,就必须使用Manifest Context Bounds。也就是说,如果数组元素类型为T,需要为类
或者函数定义[T:Manifest]泛型类型,这样才能实例化Array[T]这种泛型数组。
def packageFood[T:Manifest](food:T*)={
val foodPackage=new Array[T](food.length)
for(i <- 0 until food.length) foodPackage(i)=food(i)
foodPackage
}
8、协变和逆变
class Master
class Profession extends Master
(1)class Card[+T](val name:String) => Card[Master]是Card[Profession]的父类 协变
(2)class Card[T](val name:String) => Card[Master]与Card[Profession]没有关系
(3)class Card[-T](val name:String) => Card[Master]是Card[Profession]的子类 逆变
9、Existential Type:存在性类型,比如 Array[_]中的 _ 表示一种类型
十九、actor
1、scala的多线程编程,重启Actor trait的act方法,实现线程执行体,与java重写run方法类似,使用start()方法启动actor,
使用符号!向actor发送消息,使用receive和模式匹配接收消息
import scala.actors.Actor
class HelloActor extends Actor{
def act(){
while(true){
receive{
case name:String => println("Hello,"+name)
}
}
}
}
val helloActor= new HelloActor
helloActor.start() //启动actor
helloActor ! "leo" //发送消息
2、默认情况下,消息都是异步的,如果希望是同步的,即对方接受消息后,一定要给自己返回结果,使用 !? 发送消息,如val r=actor !? message
3、发送异步消息,不需要马上返回消息,在需要用到返回消息的地方才获取返回消息,用 !! ,如 val future = actor !! message
val reply = future()
二十、跳出循环的方法
1、通过标志 如 while(flag)
2、通过return
3、使用Breaks对象的break方法,与breakable代码块配合使用
如import scala.util.control.Breaks._
breakable{
break
}
二十一、多维数组
1、构造指定行与列的二维数组: val a = Array.ofDim[Double](3,4)
2、构造不规则多维数组
val ma = new Array[Array[Int]](3)
ma(0) = new Array[int](2)
3、java数组与scala数组的隐式转换
scala代码中,直接调用JDK(java)的API,比如调用一个java类的方法,需要传入java中的list,scala构造出来的list其实是ArrayBuffer,需要进行转换
import scala.collection.javaConversions.bufferAsJavaList //ArrayBuffer隐式转换为java list
import scala.collection.javaConversions.asScalaBuffer //java list 隐式转换为ArrayBuffer
二十二、
1、Tuple拉链操作:zip操作 a1=Array(v1) a2=Array(v2) a3=a1.zip(a2) => Array((v1.v2))
for((v1,v2) <- a3) a3.toMap
2、Java Map 与 Scala Map的隐式转换
import scala.collection.JavaConversions.mapAsScalaMap //Java Map隐式转换为Scala Map
import scala.collection.JavaConversions.mapAsJavaMap //Scala Map隐式转换为Java Map
3、内部类
(1)如果一个内部类定义在外部类里,则这个内部类是属于该外部类对象的
(2)如果一个内部类定义在伴生对象中,则这个内部类是属于该外部类的
(3)如果一个内部需要获取外部类对象,则
class A(val n:String){ outer=>
class B(val z:String){
//outer代表外部类对象
}
}
4、重写field的定义
默认情况下,如果父类中的构造函数代码,用到了会被子类重写的field,则会出现:
(1)子类构造函数调用父类的构造函数
(2)父类的构造函数初始化field(结果正确)
(3)父类构造函数执行其他构造代码,如果其他构造代码使用了该field,而且该field要被子类重写,则该field的getter方法被重写,返回0
(4)子类的构造函数执行,重写field
(5)从父类继承的其他构造代码,已经出现了错误
class Student{
val classNumber:Int=10
val classScores:Array[Int]=new Array[Int](classNumber)
}
class PEStudent extends Student{
val classNumber:int=3
}
val a = new PEStudent // a的classScores的长度只有0,而期望的长度是3
为了解决上述问题,要使用scala的一个高级特性:提前定义,在父类构造函数执行之前,先执行子类的构造函数中的某些代码
class PEStudent extends Student{
val classNumber:int=3 //该构造代码 比 父类构造函数代码 先执行
} with Student
二十三、文件操作
1、import scala.io.Source
val s = Source.fromFile("filePath","UTF-8")
val lineIterator = s.getLines //返回迭代器
for(line <- lineIterator) println(line)
val lines = s.getLines.toArray //返回数组
for(line <- lines) println(line)
val lines = s.mkString //返回文本中所有内容
for(c <- s) print(c) //遍历文件中每一个字符
val html=Source.fromURL("xxx","UTF-8") //从URL读取字符
val str=Source.fromString("Hello World") //从字符串读取字符
2、结合java IO流
二十四、偏函数
是一种高级的函数形式,其实就是没有定义好明确的输入参数的函数,函数体是一连串的case语句
偏函数是PartialFunction[A,B]类的一个实例,这个类有两个方法,apply()方法,直接调用可以通过函数体内的case进行匹配,返回结果;
另一个是isDefinedAt()方法,返回一个输入是否跟任何一个case语句匹配
val getStudentGrade:PartialFunction[String,Int] = {
case "Leo" => 90; case "Jack" => 85; case "Marry" => 95
}
getStudentGrade("Leo")
getStudentGrade.isDefinedAt("Tom")
二十五、执行外部命令
import sys.process._
"ls -ltr" ! // 使用 ! 来表示执行字符串的外部命令
二十六、正则表达
定义正则表达式: val pattern = "[a-z]+".r
val str = "hello 123 world 456"
for(matchStr <- pattern.findAllIn(str)) println(matchStr)
for(matchStr <- pattern.findFirstIn(str)) println(matchStr)
pattern.replaceAllIn(str,"zzz")
pattern.replaceFirstIn(str,"xxx")
二十七、提取器
就是定义一个包含unapply方法的对象,跟apply方法相关,apply方法是接收参数,构造出一个对象,
unapply方法是接收一个字符串,解析出对象的属性值
class Person(val name:String,val age:Int)
object Person{
def apply(name:String,age:Int) = new Person(name,age)
def unapply(str:String){
val splitIndex = str.indexOf(" ")
if(splitIndex==-1) None
else some((str.substring(0,splitIndex),str.substring(splitIndex+1)))
}
}
val Person(name,age)="leo 25" //调用提取器,变量name的值"leo",age的值为25