摘要:函數式編程與面向對象編程的類型關聯之劍目錄類型關聯關鍵字里的類型,除了在定義時會產生類型,還可以通過關鍵字來聲明類型。復合類型與關鍵字這種形式的類型稱為復合類型或者也叫交集類型。
函數式編程與面向對象編程[4]:Scala的類型關聯Type Alias
之劍 2016.5.4 23:55:19
scala里的類型,除了在定義class,trait,object時會產生類型,還可以通過type關鍵字來聲明類型。
type相當于聲明一個類型別名:
object TestMatrix extends App{ type IntList = List[Int] //接下來就可以這樣使用它: type Matrix = List[IntList] val m = Matrix( IntList(1,2,3), IntList(1,2,3), IntList(1,2,3)) }
scala> type IntList=List[Int] defined type alias IntList
這種給類型一個別名的特性只是一個小糖豆,不太甜,真正有趣的是給一類操作命名(聯想C#中定義delegate)。
比如這樣:
type PersonPredicate = Person => Boolean
接受一個Person,返回一個Boolean,我們把這一類用來判斷一個人是否符合某個條件的操作統稱為PersonPredicate。
然后我們可以定義以下predicate:
val teenagerPred: PersonPredicate = person => person.age < 20
然后前面寫過的teenagers方法就可以這樣重新定義:
def teenagers(people: People): People = { people.filter(teenagerPred) }
按照這個思路下去,我們就可以開始composite functions了。比如說,我們跟人收稅,就可以這么做:
type Tax = Person => Double val incomeTax: Tax = person => person.income * 5 / 100 val kejuanzaTax: Tax = person => person.income * 20 / 100 def giveMeYourMoney(p: Person) = { calculateTax(p, List(incomeTax, kejuanzaTax)) } def calculateTax(person: Person, taxes: List[Tax]): Double = { taxes.foldLeft(0d) { (acc, curTax) => acc + curTax(person) } }
總結一下type alia這個糖衣:
一個類型的type alias,類似于這樣的:type t = x。編譯器將在所有使用到t的地方把t替換為x。
對于一種操作的type alias,編譯器將會根據參數列表和返回值類型的不同將其替換為對應的Function0,Function1,Function2 …… 一直到Function22。
如果我們真的定義一個超過22個參數的操作會如何呢?
type twentyThree = ( String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String, String ) => String
Scala編譯器會直接告訴我們: type Function23 is not a member of package scala
結構類型結構類型(structural type)為靜態語言增加了部分動態特性,使得參數類型不再拘泥于某個已命名的類型,只要參數中包含結構中聲明的方法或值即可。舉例來說,java里對所有定義了close方法的抽象了一個Closable接口,然后再用Closable類型約束參數,而scala里可以不要求參數必須繼承自Closable接口只需要包含close方法;如下:
scala> def free( res: {def close():Unit} ) { res.close } scala> free(new { def close()=println("closed") }) closed
也可以通過type在定義類型時,將其聲明為結構類型
scala> type X = { def close():Unit } defined type alias X scala> def free(res:X) = res.close scala> free(new { def close()=println("closed") }) closed
上面傳入參數時,都是傳入一個實現close方法的匿名類,如果某個類/單例中實現了close方法,也可以直接傳入
scala> object A { def close() {println("A closed")} } scala> free(A) A closed scala> class R { def close()=print("ok") } scala> val r = new R scala> free(r) ok
結構類型還可以用在稍微復雜一點的“復合類型”中,比如:
scala> trait X1; trait X2; scala> def test(x: X1 with X2 { def close():Unit } ) = x.close
上面聲明test方法參數的類型為:
X1 with X2 { def close():Unit }
表示參數需要符合特質X1和X2同時也要有定義close方法。
復合類型與with關鍵字class A extends (B with C with D with E) T1 with T2 with T3 …
這種形式的類型稱為復合類型(compound type)或者也叫交集類型(intersection type)。
跟結構類型類似,可以在一個方法里聲明類型參數時使用復合類型:
scala> trait X1; trait X2; scala> def test(x: X1 with X2) = {println("ok")} test: (x: X1 with X2)Unit scala> test(new X1 with X2) ok scala> object A extends X1 with X2 scala> test(A) ok
也可以通過 type 聲明:
scala> type X = X1 with X2 defined type alias X scala> def test(x:X) = println("OK") test: (x: X)Unit scala> class A extends X1 with X2 scala> val a = new A scala> test(a) OK結構類型
結構類型:定義方法或者表達式時,要求傳參具有某種行為,但又不想使用類,或者接口去限制,可以使用結構類型。
class Structural { def open()=print("A class instance Opened") } object Structural__Type { def main(args: Array[String]){ init(new { def open()=println("Opened") }) //創建了一個匿名對象,實現open方法 type X = { def open():Unit } //將右邊的表達式命名為一個別名 def init(res:X) = res.open init(new { def open()=println("Opened again") }) object A { def open() {println("A single object Opened")} } //創建的單例對象里面也必須實現open方法 init(A) val structural = new Structural init(structural) } def init( res: {def open():Unit} ) { //要求傳進來的res對象具有open方法,不限制類型 res.open } }
Scala復合類型解析:
trait Compound_Type1; trait Compound_Type2; class Compound_Type extends Compound_Type1 with Compound_Type2 object Compound_Type { def compound_Type(x: Compound_Type1 with Compound_Type2) = {println("Compound Type in global method")} //限制參數x即是Type1的類型,也是Type2的類型 def main(args: Array[String]) { compound_Type(new Compound_Type1 with Compound_Type2) //匿名方式,結果:Compound Type in global method object compound_Type_oject extends Compound_Type1 with Compound_Type2 //object繼承方式,trait混入object對象中 compound_Type(compound_Type_oject) //結果都一樣,Compound Type in global method type compound_Type_Alias = Compound_Type1 with Compound_Type2 //定義一個type別名 def compound_Type_Local(x:compound_Type_Alias) = println("Compound Type in local method") //使用type別名進行限制 val compound_Type_Class = new Compound_Type compound_Type_Local(compound_Type_Class) //結果:Compound Type in local method type Scala = Compound_Type1 with Compound_Type2 { def init():Unit } //type別名限制即是Type1,也是Type2,同時還要實現init方法 } }Infix Type
Infix Type:中值類型,允許帶有兩個參數的類型。
object Infix_Types { def main(args: Array[String]) { object Log { def >>:(data:String):Log.type = { println(data); Log } } "Hadoop" >>: "Spark" >>: Log //右結合,先打印出Spark,再打印出Hadoop val list = List() val newList = "A" :: "B" :: list //中值表達式 println(newList) class Infix_Type[A,B] //中值類型是帶有兩個類型參數的類型 val infix: Int Infix_Type String = null //此時A是Int,B為String,具體類型名寫在兩個類型中間 val infix1: Infix_Type[Int, String] = null //和這種方式等價 case class Cons(first:String,second:String) //中值類型 val case_class = Cons("one", "two") case_class match { case "one" Cons "two" => println("Spark!!!") } //unapply } }self-type
class Self { self => //self是this別名 val tmp="Scala" def foo = self.tmp + this.tmp } trait S1 class S2 { this:S1 => } //限定:實例化S2時,必須混入S1類型 class S3 extends S2 with S1 class s4 {this:{def init():Unit} =>} //也能用于結構類型限定 trait T { this:S1 => } //也能用于trait object S4 extends T with S1 object Self_Types { def main(args: Array[String]) { class Outer { outer => val v1 = "Spark" class Inner { println(outer.v1) //使用外部類的屬性 } } val c = new S2 with S1 //實例化S2時必須混入S1類型 } }
--- 關于作者: 陳光劍,江蘇東海人, 號行走江湖一劍客,字之劍。程序員,詩人, 作家 http://universsky.github.io/? ---
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/65874.html
摘要:第一節函數式范式什么是函數式編程函數式編程英語或稱函數程序設計,又稱泛函編程,是一種編程范型,它將電腦運算視為數學上的函數計算,并且避免使用程序狀態以及易變對象。 第一節 函數式范式 1. 什么是函數式編程 函數式編程(英語:functional programming)或稱函數程序設計,又稱泛函編程,是一種編程范型,它將電腦運算視為數學上的函數計算,并且避免使用程序狀態以及易變對...
摘要:函數式編程與面向對象編程表達式函數柯里化高階函數之劍什么是表達式例子定義表達式是一個匿名函數,表達式基于數學中的演算得名,直接對應于其中的抽象,是一個匿名函數,即沒有函數名的函數。 函數式編程與面向對象編程[1]: Lambda表達式 函數柯里化 高階函數.md 之劍 2016.5.2 11:19:09 什么是lambda表達式 例子 For example, in Lisp the...
摘要:動態類型語言的表達力動態語言通常更方便開發較小的項目,因為可以無需聲明類型而節省了很多麻煩。 函數式編程與面向對象編程[2]: 靜態類型語言的表達力 靜態類型語言與動態類型語言 之劍 2016.5.3 21:43:20 像Java或者C#這樣強類型的準靜態語言在實現復雜的業務邏輯、開發大型商業系統、以及那些生命周期很長的應用中也有著非常強的優勢 下面我們就來學習一下這些知識. 有三...
摘要:我們的目標是建立對每一種語言的認識,它們是如何進化的,未來將走向何方。有點的味道是堅持使用動態類型,但唯一還收到合理擁泵的編程語言,然而一些在企業的大型團隊中工作的開發者擇認為這會是的一個缺陷。 為什么我們需要如此多的JVM語言? 在2013年你可以有50中JVM語言的選擇來用于你的下一個項目。盡管你可以說出一大打的名字,你會準備為你的下一個項目選擇一種新的JVM語言么? 如今借助來自...
摘要:入門,第一個這是一門很新的語言,年前后正式公布,算起來是比較年輕的編程語言了,更重要的是它是面向程序員的函數式編程語言,它的代碼運行在之上。它通過編輯類工具,帶來了先進的編輯體驗,增強了語言服務。 showImg(https://segmentfault.com/img/bV1xdq?w=900&h=385); 新的一年不知不覺已經到來了,總結過去的 2017,相信小伙們一定有很多收獲...
閱讀 3093·2023-04-26 00:53
閱讀 3544·2021-11-19 09:58
閱讀 1705·2021-09-29 09:35
閱讀 3302·2021-09-28 09:46
閱讀 3875·2021-09-22 15:38
閱讀 2700·2019-08-30 15:55
閱讀 3022·2019-08-23 14:10
閱讀 3837·2019-08-22 18:17