scala學(xué)習(xí)筆記(9-12)

目錄

  • 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á)式組

image.png

《快學(xué)Scala》第九章習(xí)題解答

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)中如何初始化該字段呢?
抽象字段在構(gòu)造中使用后,在子類(lèi)中如何初始化抽象字段
  • 解決:在子類(lèi)SavingsAccount中初始化抽象字段


    方法一:實(shí)例化時(shí)提前定義
方法二:定義類(lèi)時(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)型 =>
image.png

快學(xué)scala第十章習(xí)題答案

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種方式:

    1. valueAtOneQuarter( (x:Double) => 3 * x )
    1. valueAtOneQuarter( (x) => 3 * x )
      因?yàn)関alueAtOneQuarter知道傳入的函數(shù)類(lèi)型為(Double)=>Double所以可以省略Double
    1. valueAtOneQuarter( x => 3 * x )
      對(duì)于只有一個(gè)參數(shù)的函數(shù),可以省略外圍的()
    1. valueAtOneQuarter( 3 * _ )
      如果參數(shù)在=>右側(cè)只出現(xiàn)一次,可以用"_"替換它。
  • 注意:這些簡(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)
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

友情鏈接更多精彩內(nèi)容