Scala入门到精通——第二十三节 高级类型 (二)
本節主要內容
關于語法糖的問題,在講解程序語言時,我們常常聽到“語法糖”這個術語,在百度百科中,它具有如下定義:
語法糖(Syntactic Sugar),也叫糖衣語法, 是英國計算機科學家彼得·約翰·蘭達(Peter J. Landin)發明的一個術語。 指的是,在計算機語言中添加某種語法, 這種語法能使程序員更方便的使用語言開發程序, 同時增強程序代碼的可讀性,避免出錯的機會;但是這種語法對語言的功能并沒有影響。- 1
例如,泛型它就是一種語法糖,即使不用泛型,也能開發出同等功能的程序,例如排序算法,我可以分別實現Double、Int等類型的排序算法,但是我們使用泛型之后,可以大大簡化程序設計,減少重復代碼的編寫,代碼可讀性也有所增加。
1. 中置類型(Infix Type)
在Scala中存在著中置操作符,如1+2等,+在這被稱為中置操作符,前面我們說過,scala中的一切操作皆為對象調用,1+2其實是1.+(2)的對象方法調用。在scala中同樣存在著中置類型,如:
class Person[T,S](val name:S,val age:T)object InfixType extends App {//下面的代碼是一種中置表達方法,相當于//val p:Person[String,Int]=nullval p:String Person Int=null }- 2
可以看到,如果類的泛型參數是兩個的話,則可以使用中置表達式進行變量的定義。中置類型最常用的場景是模式匹配,例如:
//定義Person類,兩個泛型參數,分別是S,T,因此 //它是可以用中置表達式進行變量定義的 case class Person[S,T](val name:S,val age:T)object InfixType extends App {//下面的代碼是一種中置表達方法,相當于//val p:Person[String,Int]val p:String Person Int= Person("搖擺少年夢",18)//中置表達式的模式匹配用法//模式匹配時可以直接用常量,也可以直接用變量p match {case "搖擺少年夢" Person 18=> println("matching is ok")case name Person age=> println("name:"+name+" age="+age) } }2. 存在類型
在看一些scala語言實現的框架或別人寫的程序時,我們常常會發現下列形式定義的變量,例如:
object ExisitType extends App{//下面的Array[_]是一種存在類型,雖然用的是類型通配//符,但它本質上等同于//def print2(x:Array[T] forSome {type T})=println(x)//即Array[_]中的類型通匹符也是一種語法糖,用于簡化設計def print(x:Array[_])=println(x) }更多的例子如:
object ExisitType extends App{def print(x:Array[_])=println(x)def print2(x:Array[T] forSome {type T})=println(x)//Map[_,_]相當于Map[T,U] forSome {type T;type U}def print3(x:Map[_,_])=println(x)print(Array("搖擺少年夢","學途無憂網金牌講師"))print2(Array("搖擺少年夢","學途無憂網金牌講師"))print3(Map("搖擺少年夢"->"學途無憂網金牌講師")) }3. 函數類型
在scala中函數也是具有類型的,如下面的函數定義方式
//來自API文檔中的例子,Function2 object Main extends App { //max與anonfun2是等價的,它們定義的都是輸入參數是兩個Int類型 //返回值也是Int類型的函數。 val max = (x: Int, y: Int) => if (x < y) y else x//通過Funtion2定義一個輸入參數為兩個整型 //返回類型為Int的函數,這里是通過new創建創建函數 //而這個類正是Function2,它是函數類型類 val anonfun2 = new Function2[Int, Int, Int] {def apply(x: Int, y: Int): Int = if (x < y) y else x } println(max(0, 1) == anonfun2(0, 1)) }Function2對應的類型定義部分代碼如下:
trait Function2[@specialized(scala.Int, scala.Long, scala.Double) -T1, @specialized(scala.Int, scala.Long, scala.Double) -T2, @specialized(scala.Unit, scala.Boolean, scala.Int, scala.Float, scala.Long,scala.Double) +R] extends AnyRef在scala中還存在單個參數的Function類型即Function1,它的類型定義部分代碼如下:
@annotation.implicitNotFound (msg = "No implicit view available from ${T1} => ${R}.") trait Function1[@specialized(scala.Int,scala.Long, scala.Float, scala.Double/*, (scala.Unit, scala.Boolean, scala.Int,scala.Float, scala.Long, scala.Double/*,scala.AnyRef*/) +R] extends AnyRef下面的代碼給出了它的用法:
object Main extends App { val succ = (x: Int) => x + 1 val anonfun1 = new Function1[Int, Int] {def apply(x: Int): Int = x + 1 } //succ與anonfun1 函數是等價的,它們都定義了輸入參數是Int //返回值類型是Int的函數 assert(succ(0) == anonfun1(0)) }通過Function1和Function2我們可以看到,其輸入參數是逆變的,輸出參數是協變的,我們可以通過下面的代碼進行驗證:
//代碼給的是輸出類型協變的替代使用 scala> class A; class B; class C extends B defined class A defined class B defined class C //定義一個輸入類型是A,輸出類型是C的函數字面量 scala> val x= (p:A)=>new C x: A => C = <function1>//下面的代碼定義了一個變量x2,它是一個函數類型 //該函數輸入是A類型,輸出是B類型 //由于B是C的超類,Function1的輸出參數又是協變的 //因此下面的代碼是合法的 scala> val x2:A=>B = x x2: A => B = <function1> //代碼給的是輸入類型是逆變的替代使用 class R; class X; class Y extends X //創建輸入類型是X類型,輸出類型是R的函數字面量 val f1 = (x:X)=>new R //下面的代碼定義的變量f2是一個輸入類型是Y,返回值類型是R //的函數字面量,它被賦值為f1,由于輸入類型是逆變的,也就是 //說Y是X的子類型,X=>R則是Y=>R的子類型,因此下面的代碼是合法的 val f2:Y=>R = f14. 抽象類型
抽象類型是指在類或特質中利用type關鍵字定義一個沒有確定類型的標識,該標識在子類中被確定,稱這種類型為抽象類型,例如:
package cn.scala.xtwy.advancedtype//下面定義了一個抽象類 //抽象類中用type關鍵字聲明了一個抽象類型IndentityType abstract class Person1{type IdentityType//方法的返回值類型被聲明為抽象類型def getIdentityNo():IdentityType } //在子類中,對抽象類型進行具體化 class Student extends Person1{//將抽象類型具體化為String類型type IdentityType=Stringdef getIdentityNo()="123" } class Teacher extends Person1{//將抽象類型具體化為Int類型type IdentityType=Intdef getIdentityNo()=123 }object AbstractType {def main(args: Array[String]): Unit = {//返回的是String類型println(new Student().getIdentityNo())}}- 13
上述代碼的也可用泛型進行實現,如:
//使用范型參數將方法的返回值定義為抽象類型 abstract class Person2[T]{def getIdentityNo():T } //子類帶具體的類型String class Student2 extends Person2[String]{def getIdentityNo():String="123" } //子類帶具體的類型Int class Teacher extends Person2[Int]{def getIdentityNo():Int=123 } object AbstractType {def main(args: Array[String]): Unit = {//同樣返回String類型println(new Student2().getIdentityNo())}}- 6
在實際應用中,如果類型是在實例化的時候給定的,推薦用類型參數進行類的定義,例如經常需要用到new Person[String,Int](”搖擺少年夢”,18)這種創建對象的方式,此時使用泛型更為方便;如果類型是在子類型中才被確定,則推薦使用抽象類型。例如,從代碼的簡潔性方面考慮,下面的代碼使用抽象類型的話更”省“
//下面是抽象類型的定義方式
trait Closable{type intype outdef close(x:in):out }class File extends Closable{type in=Stringtype out=Booleandef close(x:in):out= true//....其它方法 }- 3
下面的代碼是類型參數的定義方式:
trait Closable[S,T]{def close(x:S):T }class File extends Closable[String,Boolean]{def close(x:String):Boolean= true//....其它方法 }當File類中還有大量的方法要用到String及Boolean類型時,抽象類型的優越性就能表現出來。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的Scala入门到精通——第二十三节 高级类型 (二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Scala入门到精通——第二十二节 高级
- 下一篇: Scala入门到精通——第二十四节 高级