zoukankan      html  css  js  c++  java
  • Scala入门到精通——第二十二节 高级类型 (一)

    作者:摇摆少年梦
    视频地址:http://www.xuetuwuyou.com/course/12

    本节主要内容

    1. this.type使用
    2. 类型投影
    3. 结构类型
    4. 复合类型

    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("摇摆少年梦"))
    }

    当涉及到继承时,这样的机制会存在些问题,比如:

    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"))
    }

    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"))
    }

    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])
    
    }

    上述代码中Outter类中的def print(i:Inner)=i 成员方法中的參数类型Inner事实上相当于def print(i:this.Inner)=idef 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")})
      }
    }

    另外结构体类型还能够用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 Cloneable

    总体 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)
      }
    }

    加入公众微信号。能够了解很多其他最新Spark、Scala相关技术资讯
    这里写图片描写叙述

  • 相关阅读:
    网游开发中的可怕群体:单机派
    关卡设计的基本理论
    游戏程序员所需的知识体系
    关于SQL Server将一列的多行内容拼接成一行的问题讨论——之一(转)
    c# lmada 修改List内容
    c# 取sqlite库分组的第一行不对
    关于SQL Server将一列的多行内容拼接成一行的问题讨论(转)
    “打包的”爱情
    “婚礼哥”隔空喊爱:我要做你一生的北京情人
    北漂,都不敢奢望爱情?
  • 原文地址:https://www.cnblogs.com/jzssuanfa/p/6993325.html
Copyright © 2011-2022 走看看