目錄
- 9.文件和正則表達(dá)式
- 10.特質(zhì)
- 11.操作符
- 12.高階函數(shù)
9.文件和正則表達(dá)式
Source.fromFile(...).getLines.toArray輸出文件的所有行
Source.fromFile(...).mkString 以字符串形式輸出文件內(nèi)容
將字符串轉(zhuǎn)換為數(shù)字,可以用toInt或toDouble方法
“正則”.r是一個(gè)Regex對(duì)象
如果你的正則表達(dá)式包含反斜杠或引號(hào)的話(huà),用"""...""",如val p = """\s+[0-9]\s+""".r
如果正則模式包含分組,你可以用如下語(yǔ)法來(lái)提取它們的內(nèi)容,for(regex(變量,...,變量)<- 字符串)
讀取行
val source = Source.fromFile("myfile.txt","UTF-8")
source.getLines
- 讀取字符 for( c <- source ) 處理c
- 讀取詞法單元和數(shù)字。 val tokens = source.mkString.split("\s+")
- 從URL或其他源讀取 source.formURL、fromString、stdin
- 讀取二進(jìn)制文件:需要使用Java類(lèi)庫(kù)
- 寫(xiě)入文本文件:使用java的PrintWriter來(lái)寫(xiě)入文本文件
訪問(wèn)目錄
- Scala沒(méi)有訪問(wèn)目錄中所有文件和遍歷所有目錄的類(lèi)。
- 自己寫(xiě)函數(shù)解決,如下:
def subdirs(dir:File):Iterator[File]={
val children = dir.listFiles().filter(_.isDirectory)
children.toIterator ++ children.toIterator.flatMap(subdirs(_))
}
def main(args: Array[String]): Unit = {
val dirStr = "C:\\Users\\zhouliang6\\Desktop\\項(xiàng)目";
val dir = new File(dirStr)
for( d <- subdirs(dir)) println(d.toString)
}
序列化
- @SeriaVersionUID(42L) class Person extends Serializable
- 如果能接受缺省ID,可以省略@SeriaVersionUID注解
- scala集合類(lèi)都是可序列化的

進(jìn)程控制
- scala.sys.process包提供了用于與shell程序交互的工具,可以用Scala編寫(xiě)shell腳本。
import sys.process._
"ls -al .."!
- ls -al ..命令被執(zhí)行,顯示上層目錄的所有文件。
- sys.process包包含一個(gè)從字符串到ProcessBuilder對(duì)象的隱式轉(zhuǎn)換,!操作符執(zhí)行的就是這個(gè)ProcessBuilder對(duì)象。
- !操作符返回結(jié)果:0:程序執(zhí)行成功。失敗顯示非0
- !!操作會(huì)以字符串形式返回。
正則表達(dá)式組

10.特質(zhì)
- 特質(zhì)中方法沒(méi)有實(shí)現(xiàn),則特質(zhì)可以當(dāng)做接口使用,子類(lèi)要實(shí)現(xiàn)特質(zhì)的接口
- 帶有具體實(shí)現(xiàn)的特質(zhì),在子類(lèi)中可以直接使用特質(zhì)的實(shí)現(xiàn)方法。
疊加在一起的特質(zhì)
- super調(diào)用特質(zhì)層級(jí)中的下一個(gè)特質(zhì),特質(zhì)從最后一個(gè)開(kāi)始被處理。
帶有特質(zhì)的對(duì)象
- 特質(zhì)B中的方法log有實(shí)現(xiàn),但是特質(zhì)B的實(shí)現(xiàn)滿(mǎn)足不了子類(lèi)Obj的需求,此時(shí)可以在構(gòu)造子類(lèi)Obj具體對(duì)象的時(shí)候混入一個(gè)更好的特質(zhì)A(A實(shí)現(xiàn)了B并且重寫(xiě)了方法log)
trait Logged {
def log (msg :String){ } //有實(shí)現(xiàn),非抽象方法
}
class SavingAccount extends Logged{
def withdraw(ammount:Double): Unit ={
log("withdraw :"+ammount)
}
}
trait ConsLogger extends Logged{ //重寫(xiě)特質(zhì)Logged的log方法
override def log(msg:String){println(msg)}
}
object SavingAccount{
def main(args: Array[String]): Unit = {
val acct = new SavingAccount with ConsLogger //構(gòu)造對(duì)象時(shí)候加入特質(zhì)
acct.withdraw(100)
}
}
特質(zhì)中抽象字段和具體字段
- 字段給出了具體值,那么字段是具體的
- 使用該特質(zhì)的類(lèi)都會(huì)獲得一個(gè)字段與之對(duì)應(yīng),這些字段不是被繼承的,而是簡(jiǎn)單地被加到了類(lèi)當(dāng)中,而超類(lèi)中的字段是被繼承的。
- 抽象字段,在一個(gè)具體的類(lèi)中必須提供值。
trait ShortLogger{
val maxLength:Int //注:該抽象字段并沒(méi)有在特質(zhì)的構(gòu)造器中使用,如果在構(gòu)造器中使用了,則下面方法有誤
}
class SavingAccount extend Account with ShortLogger{
val maxLength = 20 //不需要override
}
val acct1 = new SavingsAccount
val acct2 = new SavingsAccount with ShrotLogger{
val maxLength = 20
}
特質(zhì)構(gòu)造順序
-
構(gòu)造器由特質(zhì)字段的初始化和其他特質(zhì)中的語(yǔ)句構(gòu)成
特質(zhì)構(gòu)造順序
初始化特質(zhì)中的字段
- 特質(zhì)不能有構(gòu)造器參數(shù),每個(gè)特質(zhì)都有一個(gè)無(wú)參數(shù)的構(gòu)造器,如果特質(zhì)的構(gòu)造器中使用到了抽象字段,那么在子類(lèi)中如何初始化該字段呢?

-
解決:在子類(lèi)SavingsAccount中初始化抽象字段
方法一:實(shí)例化時(shí)提前定義


擴(kuò)展類(lèi)的特質(zhì)
- 特質(zhì)可以擴(kuò)展類(lèi),這個(gè)類(lèi)將自動(dòng)成為所有混入該特質(zhì)的超類(lèi)
trait PropertyChange extends PropertyChangeSupport{
}
class MyPoint extends PropertyChange{
}
class Test extends App{
val myp = new MyPoint
}
- 如果累已經(jīng)擴(kuò)展另一個(gè)類(lèi)怎么辦?
- 只要那是特質(zhì)超類(lèi)的一個(gè)子類(lèi)即可。
class MyPoint extends Exception with PropertyChage //錯(cuò)誤,因?yàn)镋xception不是PropertyChangeSupport的子類(lèi)
自身類(lèi)型
- 當(dāng)特質(zhì)以如下代碼開(kāi)始定義時(shí),它便只能被混入指定類(lèi)型的子類(lèi)。
this:類(lèi)型 =>

11.操作符
apply和update方法
- f(arg1,arg2,...)是函數(shù)調(diào)用語(yǔ)法,但是可以應(yīng)用到非函數(shù)和方法之外的值
- f(arg1,arg2,...) 等于 f.apply(arg1,arg2,...) //此時(shí)的f不是函數(shù)或方法
- f(arg1,arg2,...)=value 等于 f.update(arg1,arg2,...,value) //該機(jī)制只限于數(shù)組和映射

提取器
- 一個(gè)帶有unapply方法的對(duì)象,一般可以創(chuàng)建的伴生對(duì)象中,其它地方也可以。
- 從對(duì)象中提取值。
- 提取固定數(shù)量值
- 返回Option[(元組類(lèi)型)]或、單值目標(biāo)類(lèi)型的Option[類(lèi)型]、Boolean
* Name對(duì)象,其unapply方法返回一個(gè)Option[(String,String)]
object Name{
def unapply(input:String)={
val pos = input.indexOf(" ")
if( pos == -1 ) None
else Some( (input.substring(0,pos) , input.substring(pos+1) )
}
}
- 使用方式
1.變量定義時(shí)使用,如下first、last變量
val author ="Cay Horstmann"
val Name(first,last) =author
// 實(shí)際調(diào)用Name.unapply(author )并返回(Cay,Horstmann)元組,然后將元組值賦給first、last
2.模式匹配中使用
author match{
case Name(a,b) => ...a,b分別綁定到Option的值上
}
帶單個(gè)參數(shù)或無(wú)參數(shù)的提取器
- 此處的單參數(shù)和無(wú)參數(shù)不是unapply方法的參數(shù),而是提取器可傳入的參數(shù),如Name(a,b)兩個(gè)參數(shù),也就是Option返回的元組中組件個(gè)數(shù)。
- 帶unapply方法的對(duì)象
- 返回Option[Int]
- 返回Boolean
- 提取固定數(shù)量值
使用unapply提取單值,則返回一個(gè)目標(biāo)類(lèi)型Option
object Number{
def unapply(input: String ):Option[Int] ={
try{
Some( Integer.parseInt( input.trim ) )
}catch{
case ex :NumberFormatException => None
}
}
}
使用:定義變量n
val Number( n ) = "123"
- 無(wú)參:即IsCompond() 沒(méi)有參數(shù),說(shuō)明其返回的不是Option[類(lèi)型]也不是Opting[()],不然必須在IsCompond()中定義變量,那么要他干嘛?IsCompond()可以返回Boolean類(lèi)型,Boolean值不用變量來(lái)接收,而只是做一個(gè)判斷。即提取器只是測(cè)試輸入而不將值提取出來(lái)。
// unapply返回Boolean,
object IsCompond{
def unapply(input: String )= input.contains(" ")
}
使用:
author match{
case Name(a, last @ IsCompound() ) => ...a,b分別綁定到Option的值上,
}
unapplySeq方法
- 要取任意長(zhǎng)度的值得序列,應(yīng)該用unapplySeq來(lái)命名方法.
- 返回一個(gè)Option[ Seq[A] ]
- 提取不固定數(shù)量值
object Name{
def unapplySeq(input:String):= Option[ Seq[String] ]={
if( input.trim == "" ) None
else Some( input.trim.split( "\\s+" ) )
}
}
12.高階函數(shù)
作為值得函數(shù)
import scala.math._
val num =3.14
val fun = ceil _ //函數(shù)
fun(num) // 4
- ceil函數(shù)后的_意味著你確實(shí)指定的是這個(gè)函數(shù),而不是碰巧忘記了給它參數(shù)。
匿名函數(shù)
- (x: Double ) = > 3 * x
- 該函數(shù)將傳給它的參數(shù)乘以3
- Array(3, 2).map( (x: Double ) = > 3 * x ) //Array(9, 6)
- val triple = (x: Double ) = > 3 * x //存放到變量中
帶函數(shù)參數(shù)的函數(shù)
- 接受函數(shù)參數(shù)的函數(shù)叫做高階函數(shù)
- 函數(shù)類(lèi)型寫(xiě)作:(參數(shù)類(lèi)型)=>結(jié)果類(lèi)型
- 1.接收函數(shù)作為參數(shù)的函數(shù)
valueAtOneQuarter(ceil _)
def valueAtOneQuarter( f:(Double) => Double ) = f(0.25)
- valueAtOneQuarter的類(lèi)型為:結(jié)果類(lèi)型為Double,參數(shù)類(lèi)型為(Double)=>Double,所以函數(shù)類(lèi)型為( (Double)=>Double ) => Double
- 2.高階函數(shù)也可以產(chǎn)出另一個(gè)函數(shù)。
def mulBy(factor:Double) = (x :Double) => factor * x
- mulBy(3)返回匿名函數(shù)(x:Double)=>3*x。
- val quintuple = mulBy(5)
quintuple (20) //100 - mulBy的類(lèi)型為:(Double) => ( (Double) => Double )
參數(shù)(類(lèi)型)推斷
def valueAtOneQuarter( f:(Double) => Double ) =f(0.25)
valueAtOneQuarter函數(shù)接收一個(gè)函數(shù)作為參數(shù),且參數(shù)類(lèi)型為(Double)=>Double
傳入匿名函數(shù)調(diào)用,4種方式:
- valueAtOneQuarter( (x:Double) => 3 * x )
- valueAtOneQuarter( (x) => 3 * x )
因?yàn)関alueAtOneQuarter知道傳入的函數(shù)類(lèi)型為(Double)=>Double所以可以省略Double
- valueAtOneQuarter( (x) => 3 * x )
- valueAtOneQuarter( x => 3 * x )
對(duì)于只有一個(gè)參數(shù)的函數(shù),可以省略外圍的()
- valueAtOneQuarter( x => 3 * x )
- valueAtOneQuarter( 3 * _ )
如果參數(shù)在=>右側(cè)只出現(xiàn)一次,可以用"_"替換它。
- valueAtOneQuarter( 3 * _ )
注意:這些簡(jiǎn)寫(xiě)僅在參數(shù)類(lèi)型已知情況下有效。valueAtOneQuarter函數(shù)在定義時(shí)已經(jīng)知道了參數(shù)的類(lèi)型,所以可以這樣簡(jiǎn)寫(xiě)
如下4種都是相同函數(shù):
val fun = (x:Double) => 3 * x
val fun = 3 * (_:Double)
val fun = x = > 3* (x:Double) (錯(cuò)誤)
val fun = (x:Double) = > 3* (x:Double)
val fun:(Double)=>Double = 3 * _
先聲明了fun為(Double)=>Double 類(lèi)型,所以3 * _ 正確調(diào)用: fun(3) //結(jié)果:9.0
常用高階函數(shù)
- Array類(lèi)型有一個(gè)map方法,參數(shù)為函數(shù),且參數(shù)類(lèi)型為泛型。
def map[B](f: (A) ? B): [Array][B]
- 調(diào)用
(1 to 9).map("*" * _).foreach(println _)
傳入的匿名函數(shù)的非簡(jiǎn)寫(xiě)形式:(x:Int)=>"*" * x
Array("z","liang").map( "jd" + _).foreach(println _)
Array("z","liang").map( (x:String)=>"jd" + x ).foreach(println _)
傳入的匿名函數(shù)的非簡(jiǎn)寫(xiě)形式:(x:String)=>"jd" + x
柯里化
- 將原來(lái)接受兩個(gè)參數(shù)的函數(shù)變成新的接受一個(gè)參數(shù)的函數(shù)的過(guò)程。新的函數(shù)返回一個(gè)以原有第二個(gè)參數(shù)作為參數(shù)的函數(shù)。
- 接受兩個(gè)參數(shù)的函數(shù)
def mul(x:Int ,y:Int) =x * y
定義柯里化函數(shù)
- 接受一個(gè)參數(shù)的函數(shù),生成另一個(gè)接受單個(gè)參數(shù)的函數(shù)
def mulOneAtAtime(x:Int ) = (y: Int) => x * y
調(diào)用:mulOneAtAtime(6)(7) ,
調(diào)用過(guò)程mulOneAtAtime(6)結(jié)果是(y :Int)=>6 * y ,這個(gè)函數(shù)被應(yīng)用到7,最終得到42
- 簡(jiǎn)寫(xiě)定義柯里化函數(shù)
def mulOneAtAtime(x: Int)(y: Int) = x * y
目的:可以把某個(gè)函數(shù)參數(shù)單領(lǐng)出來(lái),已提供更多用于類(lèi)型推斷的信息。

控制抽象
- 將一系列語(yǔ)句組成不帶參數(shù)也沒(méi)有返回值的函數(shù)。
- 是個(gè)函數(shù)
- 沒(méi)有參數(shù)
- 沒(méi)有返回值
- 但要里面要執(zhí)行一系列語(yǔ)句
- 過(guò)程就沒(méi)有返回值也可以沒(méi)有參數(shù)
def box(){
println("hi");
Thread.sleep(1000)
}
- 把一系列語(yǔ)句傳給函數(shù)執(zhí)行,稱(chēng)為控制抽象。因?yàn)閳?zhí)行的內(nèi)容是通過(guò)外部傳過(guò)來(lái)的。函數(shù)中用來(lái)接收一系列語(yǔ)句的參數(shù)類(lèi)型為()=>Unit的函數(shù),因?yàn)樵撘幌盗姓Z(yǔ)句組成的函數(shù)不接受參數(shù)也沒(méi)有返回值。
- 舉例
def runInThread(block: ()=>Unit){
new Thread{
override def run(){ block() }
}.start()
}
- 調(diào)用
runInThread{ ()=> println("hi"); Thread.sleep(1000); }
- 省略()=>,可以使用換名調(diào)用表示法:在參數(shù)聲明和調(diào)用該函數(shù)參數(shù)的地方去掉(),但保留=>
def runInThread(block: =>Unit){
new Thread{
override def run(){ block }
}.start()
}
- 調(diào)用
runInThread{ println("hi"); Thread.sleep(1000); }
柯里化
- 第二個(gè)參數(shù)類(lèi)型為()=>Unit的函數(shù),
- 定義
- 調(diào)用
var x =10
until( x== 0) {
x -= 1
println(x)
}


