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相关技术资讯

时间: 2024-10-10 02:09:43

Scala入门到精通——第二十二节 高级类型 (一)的相关文章

Scala入门到精通——第二十节 类型參数(二)

本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对scala中的Ordering与Ordered之间的关联与差别进行解说,先看Ordering.Ordered的类继承层次体系: 通过上面两个图能够看到,Ordering混入了java中的Comparator接口.而Ordered混入了java的Comparable接口.我们知道java中的Comparator是一

Scala入门到精通——第二十四节 高级类型 (三)

作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在scala中,类(class)与类型(type)是两个不一样的概念.我们知道类是对同一类型数据的抽象,而类型则更详细. 比方定义class List[T] {}, 能够有List[Int] 和 List[String]等详细类型

Scala入门到精通——第二十七节 Scala操纵XML

本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种非常重要的半结构化数据表示方式,目前大量的应用依赖于XML,这些应用或利用XML作为数据交换格式,或利用XML进行文件配置等.像JAVA.C++及其它流行的程序开发语言都是依赖于第三方库来实现XML的操作,例如JAVA经常通过JDOM,DOM4J等XML处理工具进行XML的操纵,但Scala提供了对XML的原生支持,通过scala.xml._包下的类或

Scala入门到精通——第二十五节 提取器(Extractor)

作者:摇摆少年梦 视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们无需new操作就可以创建对象,而unapply方法则用于析构出对象,在模式匹配中特别提到,如果一个类要能够应用于模式匹配当中,必须将类声明为case class,因为一旦被定义为case class,

Scala入门到精通——第二十八节 Scala与JAVA互操作

本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接操作纵Scala类,如同Scala直接使用Java中的类一样,例如: //在Person.scala文件中定义Scala语法的Person类 package cn.scala.xtwy.scalaToJava class Person(val name:String,val age:Int) //伴

Scala入门到精通——第二十九节 Scala数据库编程

本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程上改动而来的,官方给的样例是H2数据库上的.经过本人改造,用在MySQL数据库上,官方教程地址:http://slick.typesafe.com/doc/2.1.0/sql-to-slick.html 1. Scala Mavenproject的创建 本节的project项目採用的是Maven P

Scala入门到精通——第二十节 类型参数(二)

本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对scala中的Ordering与Ordered之间的关联与区别进行讲解,先看Ordering.Ordered的类继承层次体系: 通过上面两个图可以看到,Ordering混入了java中的Comparator接口,而Ordered混入了java的Comparable接口,我们知道java中的Comparator是一

Scala入门到精通——第二十一节 类型参数(三)-协变与逆变

作者:摇摆少年梦 视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 协变 逆变 类型通匹符 1. 协变 协变定义形式如:trait List[+T] {} .当类型S是类型A的子类型时,则List[S]也可以认为是List[A}的子类型,即List[S]可以泛化为List[A].也就是被参数化类型的泛化方向与参数类型的方向是一致的,所以称为协变(covariance). 图1 协变示意图 为方便大家理解,我们先分析java语言中为什么不存在协变及下一

Scala入门到精通——第二十六节 Scala并发编程基础

作者:摇摆少年梦 视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 本节主要介绍的scala并发编程的基本思想,由于scala在2.10版本之后宣布使用akka作为其并发编程库,因此本节只进行基础性的内容介绍,后面将把重点放在akka框架的讲解上. 1. Scala并发编程简介 2003 年,Herb Sutter 在他的文章 "