Scala入门到精通——第二十二节 高级类型 (一)
2017-07-04 23:08
417 查看
本节主要内容
this.type使用类型投影
结构类型
复合类型
1. this.type使用
class Person{ private var name:String=null private var age:Int=0 def 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{ //链式调用 println(new Person().setAge(18).setName("摇摆少年梦")) }10
当涉及到继承时,这种机制会存在些问题,例如:
class Person{ private var name:String=null private var age:Int=0 def 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=null def setStudentNo(no:String)={ this.studentNo=no this } override def toString()=super.toString()+" studetNo:"+studentNo } object Main extends App{ //下面的代码会报错 //value setStudentNo is not a member of cn.scala.xtwy.advancedtype.Person println(new Student().setName("john").setAge(22).setStudentNo("2014")) }30
Student对象在调用setName、setAge方法时,返回的对象类型实质上仍然是Person类型,而Person类型并没有setStudentNo方法,从而编译出错。为解决该问题,可以将setName、setAge方法的返回值设置为:
this.type,代码如下:
class Person{ private var name:String=null private var age:Int=0 //this.type返回实际类型 def setName(name:String):this.type={ this.name=name this } def setAge(age:Int):this.type={ this.age=age this } override def toString()="name:"+name+" age:"+age } class Student extends Person{ private var studentNo:String=null def setStudentNo(no:String)={ this.studentNo=no this } 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中的内部类同类成员一类,只不过它被定义一个类而已,它具有如下的访问创建方式:class Outter{ private var x:Int=0 //内部类Inner class Inner{ def test()=x } } object TypeProject extends App{ val outter=new Outter //创建内部类的方式,同访问正常的成员变量一样 val inner=new outter.Inner println(inner.test()) }
那scala语言中不同对象创建的内部类是不是同一个类呢?其实不是,下面的代码就是证明:
import scala.reflect.runtime.universe.typeOf class Outter{ private var x:Int=0 def print(i:Inner)=i class Inner{ def test()=x } } object TypeProject extends App{ val outter=new Outter val inner=new outter.Inner val outter2=new Outter val inner2=new outter2.Inner //下面的代码编译会失败 //outter.print(inner2) //这是因为不同outter对象对应的内部类成员类型是不一样的 //这就跟两个类成员的实例它们内存地址不一样类似 //下面的类型判断会输出false //这也进一步说明了它们类型是不一样的 println(typeOf[outter.Inner]==typeOf[outter2.Inner]) }1
上述代码中Outter类中的
def print(i:Inner)=i成员方法中的参数类型Inner其实相当于
def print(i:this.Inner)=i或
def print(i:Outter.this.Inner)=i,也即它依赖于外部类,整体的话构成了一路径,因为也称为路径依赖类型。
再看下内部类的几种使用情况,它对应几种不同的路径依赖类型:
(1)类内部本身使用情况
class Outter{ private var x:Int=0 //内部使用,相当于 //private var i:Inner=new Outter.this.Inner private var i:Inner=new Inner def print(i:Inner)=i class Inner{ def test()=x } }
(2)子类使用父类中的内部类
class Outter{ private var x:Int=0 def print(i:Inner)=i class Inner{ def test()=x } } //子类中使用父类中的内部类 class A extends Outter{ private val i=new A.super.Inner }
(3)在其它类或对象中使用
object TypeProject extends App{ val outter=new Outter val inner=new outter.Inner val outter2=new Outter val inner2=new outter2.Inner }
明白几种路径依赖类型之后,我们可以对类型投影进行说明:类型投影的目的是将外部类Outter中定义的方法def print(i:Inner)=i,它可以接受做任意外部类对象中的Inner类。上面的例子当中outter与outter2中的Inner类型具有共同的父类。如下图所示:
代码如下:
import scala.reflect.runtime.universe.typeOf class Outter{ private var x:Int=0 private var i:Inner=new Outter.this.Inner //Outter#Inner类型投影的写法 //可以接受任何outter对象中的Inner类型对象 def print(i:Outter#Inner)=i class Inner{ def test()=x } } class A extends Outter{ private val i=new A.super.Inner } object TypeProject extends App{ val outter=new Outter val inner=new outter.Inner val outter2=new Outter val inner2=new outter2.Inner //下面的这个语句可以成功执行 outter.print(inner2) //注意,下面的这条语句返回的仍然是false,我们只是对print方法中的 //参数进行类型投影,并没有改变outter.Inner与outter2.Inner //是不同类的事实 println(typeOf[outter.Inner]==typeOf[outter2.Inner]) }
3. 结构类型
结构类型(Struture Type)通过利用反射机制为静态语言添加动态特性,从面使得参数类型不受限于某个已命名的的类型,例如:object StructureType { //releaseMemory中的方法是一个结构体类型,它定义了 //一个抽象方法,对close方法的规格进行了说明 def releaseMemory(res:{def close():Unit}){ res.close() } def main(args: Array[String]): Unit = { //结构体使用方式 releaseMemory(new {def close()=println("closed")}) } }6
另外结构体类型还可以用type关键字进行声明,如:
object StructureType { def releaseMemory(res:{def close():Unit}){ res.close() } //采用关键字进行结构体类型声明 type X={def close():Unit} //结构体类型X作为类型参数,定义函数releaseMemory2 def releaseMemory2(x:X)=x.close() def main(args: Array[String]): Unit = { releaseMemory(new {def close()=println("closed")}) //函数使用同releaseMemory releaseMemory2(new {def close()=println("closed")}) } }
从上面的代码来看,结构体类型其实可以看作是一个类,在函数调用时,直接通过new操作来创建一个结构体类型对象,当然它是匿名的。因此,上述方法也可以传入一个实现了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类,直接创建对象传入即可使用前述的方法 releaseMemory(new File()) //对于单例对象,直接传入单例对象即可 releaseMemory(File) } }
我们可以看到,虽然说定义的方法中的参数是一个结构体类型,但是我们也可以传入普通类对象和单例对象,只要该对象或类中具有结构体类型中声明的方法即可。上述代码也告诉 我们,其实结构体类型也是一个类,只是表现形式与类有所区别而已。
4. 复合类型
复合类型在前面的课程中其实我们已经有过接触,例如class B extends A with Cloneable1
整体 A with Cloneable可以看作是一个复合类型,它也可以通过type关键字来进行声明,例如:
class B extends A with Cloneable object CompoundType { //利用关键字type声明一个复合类型 type X=A with Cloneable def test(x:X)=println("test ok") def main(args: Array[String]): Unit = { test(new B) } }
相关文章推荐
- Scala入门到精通——第二十二节 高级类型 (一)
- Scala入门到精通——第二十二节 高级类型 (一)
- Scala入门到精通——第二十四节 高级类型 (三)
- Scala入门到精通——第二十四节 高级类型 (三)
- Scala入门到精通——第二十三节 高级类型 (二)
- Scala入门到精通——第二十四节 高级类型 (三)
- Scala入门到精通——第二十四节 高级类型 (三)
- Scala入门到精通——第二十三节 高级类型 (二)
- Scala入门之高级类型:结构类型
- Scala入门到精通——第二十一节 类型参数(三)-协变与逆变
- Scala入门之高级类型:this.type
- Scala入门到精通——第十七节 类型参数(一)
- Scala入门到精通——类型参数(一)
- Scala入门到精通——第二十节 类型参数(二)
- Scala入门之高级类型:类型投影
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
- Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构
- Scala入门到精通——第二十一节 类型参数(三)-协变与逆变