Scala入门到精通——第二十二节 高级类型 (一)
作者:摇摆少年梦
视频地址:http://www.xuetuwuyou.com/course/12
本节主要内容
- 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("摇摆少年梦"))
}
当涉及到继承时,这样的机制会存在些问题,比如:
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)=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")})
}
}
另外结构体类型还能够用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入门到精通——第二十二节 高级类型 (一)的更多相关文章
- Scala入门到精通——第二十四节 高级类型 (三)
作者:摆摆少年梦 视频地址:http://blog.csdn.net/wsscy2004/article/details/38440247 本节主要内容 Type Specialization Man ...
- Scala入门到精通——第二十九节 Scala数据库编程
本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...
- Scala入门到精通——第二十七节 Scala操纵XML
本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种很重要的半结构化数据表示方式,眼下大量的应用依赖于XM ...
- Scala入门到精通
原文出自于: http://my.csdn.net/lovehuangjiaju 感谢! 也感谢,http://m.blog.csdn.net/article/details?id=52233484 ...
- SaltStack 入门到精通第二篇:Salt-master配置文件详解
SaltStack 入门到精通第二篇:Salt-master配置文件详解 转自(coocla):http://blog.coocla.org/301.html 原本想要重新翻译salt-mas ...
- 网络安全从入门到精通(第二章-3)后端基础SQL— MySQL高级查询与子查询
本文内容: MySQL的基础查询语句 链接查询 联合查询 子查询 渗透测试常用函数 1,MySQL基础查询语句: select * from 表 order by ASC/DESC; ASC:从小到 ...
- Scala入门到精通——第十五节 Case Class与模式匹配(二)
本节主要内容 模式匹配的类型 for控制结构中的模式匹配 option类型模式匹配 1. 模式的类型 1 常量模式 object ConstantPattern{ def main(args: Arr ...
- Scala入门到精通——第十九节 隐式转换与隐式參数(二)
作者:摇摆少年梦 配套视频地址:http://www.xuetuwuyou.com/course/12 本节主要内容 隐式參数中的隐式转换 函数中隐式參数使用概要 隐式转换问题梳理 1. 隐式參数中的 ...
- Scala入门到精通——第十六节 泛型与注解
本节主要内容 泛型(Generic Type)简单介绍 注解(Annotation)简单介绍 注解经常使用场景 1. 泛型(Generic Type)简单介绍 泛型用于指定方法或类能够接受随意类型參数 ...
随机推荐
- VirtualBox中Linux虚拟机与主机共享文件夹
VirtualBox中Linux虚拟机与主机共享文件夹 一.Linux虚拟机安装增强功能 二.点击虚拟机 设置-->选择 共享文件夹-->点击右侧的带加号的文件夹图标,执行下面的操作1. ...
- Linux常用音乐播放器
1.Rhythmbox是一个音乐播放和管理应用,GNOME桌面环境自带,它可以播放各种音频格式的音乐管理收藏的音乐.同时还具有音乐回放.音乐导入.刻录音频CD.显示专辑封面.显示歌词.DAAP共享等功 ...
- 请允许我成为你的夏季——shiro、jdbcInsertall
这两天总是觉得自己被关进了一个大笼子,日子拮据.生活不就是这样吗,一边觉得自己很差劲,一边又想成为一个更好的自己.可那又有什么办法呢,万物皆有裂痕,但那又怎样,那是光照进来的地方啊. 开始学习shir ...
- 天意——thinkphp方法名大小写问题
今天星期六,晚一小时上班.早起后背了会单词就骑自行车上班了.我是个有豪车梦的男生,每看到什么保时捷啊,雷克萨斯啊开过都会呆呆的看一会.现在虽然我买不上车,但是我可以靠我自己先买一台帅气的大摩托啊哈哈. ...
- react基础用法二(组件渲染)
react基础用法二(组件渲染) 如图所示组件可以是函数 格式:function 方法名(){ return <标签>内容</标签>} 渲染格式: <方法名 /> ...
- python第六次作业——随笔
第一就是教的和布置的作业难度不一样.python在课堂上学到的东西太基础.然而作业基本上在教义是不能直接找到公式照搬的(尤其是第五次作业文件处理要用到pandas和numpy),所以做作业只能自己去找 ...
- iOS 热门高效开源库集锦,收藏备用
一.推荐使用的第三方库 1:基于响应式编程思想的ReactiveCocoa 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:iOS解耦与组件化开 ...
- LeetCode 258 Add Digits(数字相加,数字根)
翻译 给定一个非负整型数字,反复相加其全部的数字直到最后的结果仅仅有一位数. 比如: 给定sum = 38,这个过程就像是:3 + 8 = 11.1 + 1 = 2.由于2仅仅有一位数.所以返回它. ...
- HDU 2846 Repository (字典树 后缀建树)
Repository Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Total ...
- EC2 开启 IPV6 访问 和 禁止重启后自动分配IP地址
EC2 开启 IPV6 访问 和 禁止重启后自动分配IP地址进入 VPC 控制台,对当前 VPC 添加 IPV6 CIDR 块对该 VPC 的路由表进行修改,添加其它路由,第一个空填::/0,第二个空 ...