作者:摇摆少年梦

视频地址: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. VirtualBox中Linux虚拟机与主机共享文件夹

    VirtualBox中Linux虚拟机与主机共享文件夹 一.Linux虚拟机安装增强功能 二.点击虚拟机 设置-->选择 共享文件夹-->点击右侧的带加号的文件夹图标,执行下面的操作1. ...

  2. Linux常用音乐播放器

    1.Rhythmbox是一个音乐播放和管理应用,GNOME桌面环境自带,它可以播放各种音频格式的音乐管理收藏的音乐.同时还具有音乐回放.音乐导入.刻录音频CD.显示专辑封面.显示歌词.DAAP共享等功 ...

  3. 请允许我成为你的夏季——shiro、jdbcInsertall

    这两天总是觉得自己被关进了一个大笼子,日子拮据.生活不就是这样吗,一边觉得自己很差劲,一边又想成为一个更好的自己.可那又有什么办法呢,万物皆有裂痕,但那又怎样,那是光照进来的地方啊. 开始学习shir ...

  4. 天意——thinkphp方法名大小写问题

    今天星期六,晚一小时上班.早起后背了会单词就骑自行车上班了.我是个有豪车梦的男生,每看到什么保时捷啊,雷克萨斯啊开过都会呆呆的看一会.现在虽然我买不上车,但是我可以靠我自己先买一台帅气的大摩托啊哈哈. ...

  5. react基础用法二(组件渲染)

    react基础用法二(组件渲染) 如图所示组件可以是函数 格式:function 方法名(){ return <标签>内容</标签>} 渲染格式: <方法名 />  ...

  6. python第六次作业——随笔

    第一就是教的和布置的作业难度不一样.python在课堂上学到的东西太基础.然而作业基本上在教义是不能直接找到公式照搬的(尤其是第五次作业文件处理要用到pandas和numpy),所以做作业只能自己去找 ...

  7. iOS 热门高效开源库集锦,收藏备用

    一.推荐使用的第三方库 1:基于响应式编程思想的ReactiveCocoa 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:iOS解耦与组件化开 ...

  8. LeetCode 258 Add Digits(数字相加,数字根)

    翻译 给定一个非负整型数字,反复相加其全部的数字直到最后的结果仅仅有一位数. 比如: 给定sum = 38,这个过程就像是:3 + 8 = 11.1 + 1 = 2.由于2仅仅有一位数.所以返回它. ...

  9. HDU 2846 Repository (字典树 后缀建树)

    Repository Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total ...

  10. EC2 开启 IPV6 访问 和 禁止重启后自动分配IP地址

    EC2 开启 IPV6 访问 和 禁止重启后自动分配IP地址进入 VPC 控制台,对当前 VPC 添加 IPV6 CIDR 块对该 VPC 的路由表进行修改,添加其它路由,第一个空填::/0,第二个空 ...