Scala入门到精通——第二十二节 高级类型 (一)
本節(jié)主要內(nèi)容
1. this.type使用
class Person{private var name:String=nullprivate var age:Int=0def setName(name:String)={this.name=name//返回對象本身this}def setAge(age:Int)={this.age=age//返回對象本身this}override def toString()="name:"+name+" age:"+age }object Main extends App{//鏈?zhǔn)秸{(diào)用println(new Person().setAge(18).setName("搖擺少年夢")) }- 10
當(dāng)涉及到繼承時,這種機(jī)制會存在些問題,例如:
class Person{private var name:String=nullprivate var age:Int=0def setName(name:String)={this.name=name//返回Person對象本身this}def setAge(age:Int)={this.age=age//返回Person對象本身this}override def toString()="name:"+name+" age:"+age }class Student extends Person{private var studentNo:String=nulldef setStudentNo(no:String)={this.studentNo=nothis}override def toString()=super.toString()+" studetNo:"+studentNo }object Main extends App{//下面的代碼會報錯//value setStudentNo is not a member of cn.scala.xtwy.advancedtype.Personprintln(new Student().setName("john").setAge(22).setStudentNo("2014")) }- 30
Student對象在調(diào)用setName、setAge方法時,返回的對象類型實(shí)質(zhì)上仍然是Person類型,而Person類型并沒有setStudentNo方法,從而編譯出錯。為解決該問題,可以將setName、setAge方法的返回值設(shè)置為:this.type ,代碼如下:
class Person{private var name:String=nullprivate var age:Int=0//this.type返回實(shí)際類型def setName(name:String):this.type={this.name=namethis}def setAge(age:Int):this.type={this.age=agethis}override def toString()="name:"+name+" age:"+age }class Student extends Person{private var studentNo:String=nulldef setStudentNo(no:String)={this.studentNo=nothis}override def toString()=super.toString()+" studetNo:"+studentNo }object Main extends App{//println(new Person().setAge(18).setName("搖擺少年夢"))println(new Student().setName("john").setAge(22).setStudentNo("2014")) }- 1
2. 類型投影
我們知道,Scala中的內(nèi)部類同類成員一類,只不過它被定義一個類而已,它具有如下的訪問創(chuàng)建方式:
class Outter{private var x:Int=0//內(nèi)部類Innerclass Inner{def test()=x} }object TypeProject extends App{val outter=new Outter//創(chuàng)建內(nèi)部類的方式,同訪問正常的成員變量一樣val inner=new outter.Innerprintln(inner.test())}那scala語言中不同對象創(chuàng)建的內(nèi)部類是不是同一個類呢?其實(shí)不是,下面的代碼就是證明:
import scala.reflect.runtime.universe.typeOf class Outter{private var x:Int=0def print(i:Inner)=iclass Inner{def test()=x} }object TypeProject extends App{val outter=new Outterval inner=new outter.Innerval outter2=new Outterval inner2=new outter2.Inner//下面的代碼編譯會失敗//outter.print(inner2)//這是因為不同outter對象對應(yīng)的內(nèi)部類成員類型是不一樣的//這就跟兩個類成員的實(shí)例它們內(nèi)存地址不一樣類似//下面的類型判斷會輸出false//這也進(jìn)一步說明了它們類型是不一樣的println(typeOf[outter.Inner]==typeOf[outter2.Inner])}- 1
上述代碼中Outter類中的def print(i:Inner)=i 成員方法中的參數(shù)類型Inner其實(shí)相當(dāng)于def print(i:this.Inner)=i 或def print(i:Outter.this.Inner)=i ,也即它依賴于外部類,整體的話構(gòu)成了一路徑,因為也稱為路徑依賴類型。
再看下內(nèi)部類的幾種使用情況,它對應(yīng)幾種不同的路徑依賴類型: 
 (1)類內(nèi)部本身使用情況
(2)子類使用父類中的內(nèi)部類
class Outter{private var x:Int=0def print(i:Inner)=iclass Inner{def test()=x} } //子類中使用父類中的內(nèi)部類 class A extends Outter{private val i=new A.super.Inner }(3)在其它類或?qū)ο笾惺褂?/p> object TypeProject extends App{val outter=new Outterval inner=new outter.Innerval outter2=new Outterval inner2=new outter2.Inner }
明白幾種路徑依賴類型之后,我們可以對類型投影進(jìn)行說明:類型投影的目的是將外部類Outter中定義的方法def print(i:Inner)=i,它可以接受做任意外部類對象中的Inner類。上面的例子當(dāng)中outter與outter2中的Inner類型具有共同的父類。如下圖所示:
代碼如下:
import scala.reflect.runtime.universe.typeOf class Outter{private var x:Int=0private var i:Inner=new Outter.this.Inner//Outter#Inner類型投影的寫法//可以接受任何outter對象中的Inner類型對象def print(i:Outter#Inner)=iclass Inner{def test()=x} }class A extends Outter{private val i=new A.super.Inner }object TypeProject extends App{val outter=new Outterval inner=new outter.Innerval outter2=new Outterval inner2=new outter2.Inner//下面的這個語句可以成功執(zhí)行outter.print(inner2)//注意,下面的這條語句返回的仍然是false,我們只是對print方法中的//參數(shù)進(jìn)行類型投影,并沒有改變outter.Inner與outter2.Inner//是不同類的事實(shí)println(typeOf[outter.Inner]==typeOf[outter2.Inner]) }3. 結(jié)構(gòu)類型
結(jié)構(gòu)類型(Struture Type)通過利用反射機(jī)制為靜態(tài)語言添加動態(tài)特性,從面使得參數(shù)類型不受限于某個已命名的的類型,例如:
object StructureType {//releaseMemory中的方法是一個結(jié)構(gòu)體類型,它定義了//一個抽象方法,對close方法的規(guī)格進(jìn)行了說明def releaseMemory(res:{def close():Unit}){res.close() }def main(args: Array[String]): Unit = {//結(jié)構(gòu)體使用方式releaseMemory(new {def close()=println("closed")})} }- 6
另外結(jié)構(gòu)體類型還可以用type關(guān)鍵字進(jìn)行聲明,如:
object StructureType {def releaseMemory(res:{def close():Unit}){res.close() }//采用關(guān)鍵字進(jìn)行結(jié)構(gòu)體類型聲明type X={def close():Unit}//結(jié)構(gòu)體類型X作為類型參數(shù),定義函數(shù)releaseMemory2def releaseMemory2(x:X)=x.close()def main(args: Array[String]): Unit = {releaseMemory(new {def close()=println("closed")})//函數(shù)使用同releaseMemoryreleaseMemory2(new {def close()=println("closed")})} }從上面的代碼來看,結(jié)構(gòu)體類型其實(shí)可以看作是一個類,在函數(shù)調(diào)用時,直接通過new操作來創(chuàng)建一個結(jié)構(gòu)體類型對象,當(dāng)然它是匿名的。因此,上述方法也可以傳入一個實(shí)現(xiàn)了close方法的類或單例對象
//定義一個普通的scala類,其中包含了close成員方法 class File{def close():Unit=println("File Closed") } //定義一個單例對象,其中也包含了close成員方法 object File{def close():Unit=println("object File closed") }object StructureType {def releaseMemory(res:{def close():Unit}){res.close() }type X={def close():Unit}def releaseMemory2(x:X)=x.close()def main(args: Array[String]): Unit = {releaseMemory(new {def close()=println("closed")})releaseMemory2(new {def close()=println("closed")})//對于普通的scala類,直接創(chuàng)建對象傳入即可使用前述的方法releaseMemory(new File())//對于單例對象,直接傳入單例對象即可releaseMemory(File)} }我們可以看到,雖然說定義的方法中的參數(shù)是一個結(jié)構(gòu)體類型,但是我們也可以傳入普通類對象和單例對象,只要該對象或類中具有結(jié)構(gòu)體類型中聲明的方法即可。上述代碼也告訴 我們,其實(shí)結(jié)構(gòu)體類型也是一個類,只是表現(xiàn)形式與類有所區(qū)別而已。
4. 復(fù)合類型
復(fù)合類型在前面的課程中其實(shí)我們已經(jīng)有過接觸,例如
class B extends A with Cloneable- 1
整體 A with Cloneable可以看作是一個復(fù)合類型,它也可以通過type關(guān)鍵字來進(jìn)行聲明,例如:
class B extends A with Cloneableobject CompoundType {//利用關(guān)鍵字type聲明一個復(fù)合類型type X=A with Cloneabledef test(x:X)=println("test ok")def main(args: Array[String]): Unit = {test(new B)} }總結(jié)
以上是生活随笔為你收集整理的Scala入门到精通——第二十二节 高级类型 (一)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: Scala入门到精通——第二十一节 类型
- 下一篇: Scala入门到精通——第二十三节 高级
