作者:摇摆少年梦

视频地址: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相关技术资讯

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

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

    作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...

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

    本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...

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

    本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种很重要的半结构化数据表示方式,眼下大量的应用依赖于XM ...

  4. Scala入门到精通

    原文出自于: http://my.csdn.net/lovehuangjiaju 感谢! 也感谢,http://m.blog.csdn.net/article/details?id=52233484 ...

  5. SaltStack 入门到精通第二篇:Salt-master配置文件详解

    SaltStack 入门到精通第二篇:Salt-master配置文件详解     转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...

  6. 网络安全从入门到精通(第二章-3)后端基础SQL— MySQL高级查询与子查询

    本文内容: MySQL的基础查询语句 链接查询 联合查询 子查询 渗透测试常用函数 1,MySQL基础查询语句: select * from 表 order  by ASC/DESC; ASC:从小到 ...

  7. Scala入门到精通——第十五节 Case Class与模式匹配(二)

    本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{ def main(args: Arr ...

  8. Scala入门到精通——第十九节 隐式转换与隐式參数(二)

    作者:摇摆少年梦 配套视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 隐式參数中的隐式转换 函数中隐式參数使用概要 隐式转换问题梳理 1. 隐式參数中的 ...

  9. Scala入门到精通——第十六节 泛型与注解

    本节主要内容 泛型(Generic Type)简单介绍 注解(Annotation)简单介绍 注解经常使用场景 1. 泛型(Generic Type)简单介绍 泛型用于指定方法或类能够接受随意类型參数 ...

随机推荐

  1. DNS A记录和CNAME记录

    参考文章:http://blog.xieyc.com/differences-between-a-record-and-cname-record/ A (Address) 记录是用来指定主机名(或域名 ...

  2. Xml、Json序列化

    Xml序列化: public class XmlHelper { private static string XmlPath = Path.Combine(AppDomain.CurrentDomai ...

  3. vue父子间通信案列三($emit和prop用法)

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  4. 利用 urandom 生成随机密码

    cat /dev/urandom | LC_ALL=C tr -dc "[:alnum:]" | fold -w 16 |head -3   说明: fold -w 16  指定密 ...

  5. 今日SGU 5.15

    最近事情好多,数据库作业,没天要学2个小时java,所以更新的sgu就比较少了 SGU 131 题意:给你两种小块一种,1*1,一种2*2-1*1,问你填满一个m*n的矩形有多少钟方法,n和m小于等于 ...

  6. qt程序实现打开文件夹

    QString path=QDir::currentPath();//获取程序当前目录 path.replace("/","\\");//将地址中的" ...

  7. ArcGIS Engine中的重点类库介绍

    转自原文ArcGIS Engine中的重点类库介绍 System类库 System类库是ArcGIS体系结构中最底层的类库.System类库包含给构成ArcGIS的其他类库提供服务的组件.System ...

  8. Linux下使用fstatfs/statfs查询系统相关信息

    Linux下使用fstatfs/statfs查询系统相关信息 1.   功能 #include < sys/statfs.h > int statfs(const char *path, ...

  9. LinkedIn Cubert 实践指南

    · LinkedIn Cubert安装指南 · Understanding Cubert Concepts(一)Partitioned Blocks · Understanding Cubert Co ...

  10. 什么时候用button,什么时候用a标签

    什么时候用button,什么时候用a标签 一.问题 能实现链接功能的标签一般就a标签,button标签,input submit标签 input submit肯定是提交表单的时候用 那什么时候用but ...