日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Scala笔记

發(fā)布時間:2023/12/10 编程问答 29 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Scala笔记 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

1、伴生對象

形如:
有一個類
class Test{
}
一個object和該類同名
object Test{
}

object Test的作用類似于靜態(tài)類(工具類),其中的所有成員都是靜態(tài)的,在object Test中可以直接訪問class Test的成員;反之,class Test中要通過object Test來引用其成員例如使用Test.的方式

2、apply方法

class中的apply:是一個比較特殊的方法,通過這個class new 出來的對象,可以直接通過對象(),這樣的方式來調(diào)用apply方法

object中的apply:比較常用,例如,通常使用數(shù)組時是下面這樣的代碼:

val arr = new Array[Int](3) arr(0) = 1 arr(1) = 2 arr(2) = 3

但是,在scala中可以通過伴生對象的apply方法,我們可以很方便的構(gòu)建類的對象,而不必知道和操作這個過程,如下:

val arr = Array(1,2,3)

通過伴生對象的apply方法,我們可以很方便的構(gòu)建類的對象,而不必知道和操作這個過程,在apply方法中其實也是new出一個Array,并在其中做好了初始化操作
源代碼如下:

/** Creates an array of `Int` objects */// Subject to a compiler optimization in Cleanup, see above.def apply(x: Int, xs: Int*): Array[Int] = {val array = new Array[Int](xs.length + 1)array(0) = xvar i = 1for (x <- xs.iterator) { array(i) = x; i += 1 }array}

3、繼承

沒啥好說的,概念和其他語言一樣,只是語法有點區(qū)別:

class Father(name:String){ ... } //構(gòu)造子類的時候會先構(gòu)造父類,所以要將父類構(gòu)造函數(shù)需要的參數(shù)給它 class Son(name:String,age:Int) extends Father(name){ ... }

4、trait特質(zhì)

trait可以當接口來用,但是和其他語言的接口有些不同,trait里面竟然還可以有方法的定義!
那么這樣和抽象類不是一樣的了,干嘛還要trait?
Scala中也是單繼承,也就是說一個類只能繼承一個父類,需要有很多子類的特性的時候就可以通過繼承多個trait來實現(xiàn)(可以把抽象類看成是一個統(tǒng)一的模板,trait則是其他七七八八的裝飾,可加可減靈活性高)

在Scala中如果一個class,或者一個trait直接繼承了另外一個trait,那么語法是一樣的:

trait Test{ ... }class Test1 extends Test{ ... }

當多重繼承時,trait要使用with關(guān)鍵字,構(gòu)造順序從左往右,且不重復構(gòu)造:

class Human{...} trait ITeacher extends Human{...} trait IBasketballPlayer extends Human{...} class BasketballTeacher extends Human with ITeacher with IBasketballPlayer{...}

由于ITeacher和IBasketballPlayer都繼承了Human,理論上在構(gòu)造他們的時候會去構(gòu)造他們的父類,也就是Human,但是由于Human之間在構(gòu)造BasketballTeacher 的時候已經(jīng)構(gòu)造過了,所以這里不再重復構(gòu)造

上面代碼演示的是在定義class的時候混入trait
實際上也可以在new object的時候使用,這樣可以在具體的場景中定義具體處理的對象(和定義class的時候直接混入的區(qū)別是,前者new出來的所有object都帶有trait特質(zhì)的,后者只作用在一個單一的object):

class Human{...} trait ITeacher extends Human{...} trait IBasketballPlayer extends Human{...}val t1 = new Human with ITeacher with IBasketballPlayer{ //如果有抽象方法,在此重寫 }

需要注意的是,混入的trait必須都繼承自同一個父類

trait的AOP實現(xiàn):

trait DoSomething {def work }class Do extends DoSomething{override def work: Unit = {println("working!")} }trait BeforeAndAfter extends DoSomething {abstract override def work: Unit = {println("init...")super.workprintln("destroy...")} }object test {def main(args: Array[String]) {val worker = new Do with BeforeAndAfterworker.work} }

上面的代碼中,使用trait實現(xiàn)了一個簡單的AOP編程實例

首先定義了一個trait DoSomething,里面有一個抽象方法work
class Do繼承自DoSomething,并實現(xiàn)了具體的work方法

這時new一個Do的object之后調(diào)用work應該打印出一行記錄
之后定義了另外一個trait BeforeAndAfter,也繼承了DoSomething并重寫work

在其重寫的方法中將父trait的work方法放在初始化和銷毀的操作之間,由于父trait的work方法是抽象的,此時又調(diào)用了這個抽象方法,所以這個重寫的work仍然是抽象的,要加上abstract關(guān)鍵字

在new Do的object的時候混入這個trait就可以實現(xiàn)AOP,代碼執(zhí)行過程應該是這樣的:
1、調(diào)用worker的work方法,由于混入了trait,所以實際調(diào)用的是這個trait里面的work
2、這個trait里面的work先進行了初始化操作,然后調(diào)用父trait的work,而這個方法的具體實現(xiàn)是在Do類中完成的,所以又調(diào)用了Do類中的具體work實現(xiàn)
3、work調(diào)用完成之后,進行銷毀操作

5、包對象

包對象的定義及作用如下:

//這是一個包對象 package obejct Person{...} //這是一個包的定義 package Person{ //此時,在這個包的作用于范圍之內(nèi),可以直接訪問包對象的成員 }//使用這種語法的import意思是將scala包中的StringBuilder隱藏起來不使用(使用別的包的StringBuilder) import scala.{StringBuilder => _}

6、文件操作

//讀取本地文件 val localFile = Source.fromFile("file path") val lines = localFile.getLines //讀取網(wǎng)絡文件 val networkFile = Source.fromURL("file url") //創(chuàng)建一個寫入器 val writer = new PrintWriter(new File("file path")) writer.println("something to write") writer.close //控制臺讀取 Console.readLine

7、正則表達式

//可以直接使用字符串.r的方式返回一個Regex對象 val regex1 = "[0-9]+".r //三個引號表示表達式中的符號都是原意,而不是轉(zhuǎn)義符(如\) val regex2 = """\s+[0-9]+\s+""".r //Regex對象可以直接調(diào)用findAllIn/findFirstIn等方法 regex1.findAllIn("1234 dqd qwdq")//該方法會返回全部匹配項

正則表達式和模式匹配相結(jié)合

val regex = """([0-9]+) ([a-z]+)""".r val line = "123 abc" line match { //line如果符合regex1規(guī)則,會將其自動匹配成(num,str)格式 case regex(num, str) => println(num + ":" + str) case _ => println("~~~~~~~~~`") }

8、內(nèi)部函數(shù)的定義

開發(fā)過程中,經(jīng)常將各個子功能定義為一個個函數(shù),在通過一個統(tǒng)一入口函數(shù)在調(diào)用這個子函數(shù)
但是這樣存在一個問題,入口函數(shù)和子函數(shù)通常是定義在一起的,既然入口函數(shù)可以被外部調(diào)用,那么子函數(shù)同樣也可以
這就不是我們想要的效果了,我們需要實現(xiàn)的是外部只能調(diào)用入口函數(shù),而對于其他的子功能都是不可見的
這也就是高內(nèi)聚低耦合的思想

在Scala中,函數(shù)是一等公民,意味著函數(shù)可以當做變量成員來使用
那么,在函數(shù)中可以定義變量,也就可以定義函數(shù)
這就是內(nèi)部函數(shù)

def portal{//內(nèi)部函數(shù)定義def action1{}def action2{}...調(diào)用內(nèi)部函數(shù)action1action2 }

9、閉包

簡單的說,閉包就是指在一個函數(shù)中,能夠訪問另外一個函數(shù)的變量(必須要訪問這個變量才能完成函數(shù)的工作),讀取這個變量之后,這個函數(shù)就關(guān)閉執(zhí)行,成為閉包
一個簡單的閉包例子:

//這個函數(shù)中,要完成功能必須要知道m(xù)ore的值 def add(more:Int) = (x:Int) => x + more //傳入more的值為1,返回值其實還是一個函數(shù)x+1 val a = add(9) val b = add(90) //調(diào)用這個返回的函數(shù),傳入x=1 a(1) b(10)

10、高階函數(shù)

高階函數(shù)簡單的說就是 參數(shù)是函數(shù) 的函數(shù)
例如map、reduce等需要傳入匿名函數(shù)的函數(shù)
具體操作就不詳細說明了,因為高階函數(shù)太多了= =使用方法都是差不多的

11、SAM轉(zhuǎn)換

即Simple Abstract Method
在例如Java等語言中,代碼通常是這樣子寫的:

jButton.addActionListener(new ActionListener{override def actionPerformed(event:ActionEvent){counter += 1} })

jButton的addActionListener需要一個格式為(event:ActionEvent)=>Unit的方法,上面的代碼中直接new出了一個ActionListener并重寫其方法傳入
這叫做樣本代碼,即符合這個樣本格式的方法才能使用
而很多時候,addActionListener這類的方法并不需要知道這么多信息,它只需要我們給它一個方法就行了,而不是一大堆的重新new對象,重寫方法

在Scala中是這么解決問題的:

//這是一個隱式轉(zhuǎn)換,其實起到的作用就是樣本代碼,名字任意,只要參數(shù)和返回值是符合固定格式的即可 implicit def makeAction(action:(ActionEvent) => Unit) = {new ActionListener{override def actionPerformed(event:ActionEvent){action(event)} }//有了上面的隱式轉(zhuǎn)換,我們就可以很簡潔的直接將方法當做參數(shù)傳入 jButton.addActionListener((event:ActionEvent) => counter += 1)

此時,在這個界面的所有地方,都可以傳入(ActionEvent) => Unit類型的函數(shù)給需要的函數(shù)了

總結(jié)SAM轉(zhuǎn)換:
借助隱式轉(zhuǎn)換,將樣本代碼省去
傳入一個方法,自動掃描當前區(qū)域的隱式轉(zhuǎn)換(定義了樣本代碼),如果轉(zhuǎn)換成功就可以調(diào)用

12、Currying函數(shù)柯里化

函數(shù)的柯里化即將原來接受兩個參數(shù)的函數(shù)變成新的接受一個參數(shù)的函數(shù)的過程。
簡單的例子:

//多參數(shù)的函數(shù) def add(x:Int,y:Int) = x + y add(1,2) //接受一個參數(shù)的函數(shù) def add(x:Int) = (y:Int) => x + y add(1)(2)

對于只接受一個參數(shù)的函數(shù)格式是不是挺熟悉的?在之前的閉包中使用的就是這種格式的函數(shù)
Scala中支持定義簡介的柯里化函數(shù)

def add(x:Int)(y:Int) = x + y

柯里化的作用有很多,其中一個就是用來做類型推斷
在一些場合,Scala編譯器可以通過第一個參數(shù)的類型推薦第二個參數(shù)的類型以便進行一些操作

13、模式匹配

Scala的模式匹配類似于switch,但是更加靈活,格式如下:

val line = ... line match{case ... => ......case _ => ... }

每個case都有返回值(沒有特殊指定的話)
case分支不用break
case后可以用常亮,變量,表達式,方法等

模式匹配還有很多其他的特殊的用法
例如:匹配type,array、list、tuple格式

def match_type(t:Any) = t match{case i:Int => println("Int")case s:String => println("String")case m:Map[_,_] => m.foreach(println) }def match_array(arr:Any) = arr match{//數(shù)組中只有一個0的匹配成功case Array(0) => ...//數(shù)組中有任意的兩個數(shù)匹配成功case Array(x,y) => ...//數(shù)組中第一個為0,還有任意多個元素的匹配成功case Array(0,_*) => ... }def match_list(lst:Any) = lst match{//List中有一個0的匹配成功(Nil表示一個空的List,::運算符是從右至左運算的,表示空List加上一個0元素,即為只有一個0的List集合)case 0 :: Nil => ...//List中有任意的兩個數(shù)匹配成功case x :: y :: Nil => ...//集合中第一個為0,還有任意多個元素的匹配成功(tail表示List中除了第一個元素外的所有元素)case 0 :: tail => ... }

14、樣例類和樣例對象

通常在系統(tǒng)開發(fā)中,我們需要自己定義一些數(shù)據(jù)結(jié)構(gòu)來進行統(tǒng)一的消息傳遞,例如經(jīng)常使用的Model
在Scala中,使用樣例類和樣例對象來完成這個功能
定義的格式如下:

case class Person(...) case object Person1(...)

15、嵌套的樣例類和模式匹配結(jié)合

abstract class Item{...} case class Book(name:String,price:Int) extends Item //BookList中嵌套了一個Book的樣例類 case class BookList(num:Int,books:Book*) extends Itemdef match_caseclass(item:Item) = item match{//匹配BookList,用占位符_代替的屬性都不關(guān)心,只要Book的name屬性case BookList(_,Book(name,_),_*) => ...//可以使用別名@Book的方式進行模式匹配,后面的方法體中可以使用別名直接操作case BookList(_,b1 @ Book(_,_),other @ _*) => ... }

未完待續(xù)…

轉(zhuǎn)載于:https://www.cnblogs.com/jchubby/p/5449381.html

創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎

總結(jié)

以上是生活随笔為你收集整理的Scala笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。