Scala入门到精通——第二十三节 高级类型 (二)
本节主要内容
- 中置类型(Infix Type)
- 存在类型
- 函数类型
- 抽象类型
关于语法糖的问题,在讲解程序语言时,我们常常听到“语法糖”这个术语,在百度百科中,它具有如下定义:
语法糖(Syntactic Sugar),也叫糖衣语法,
是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。
指的是,在计算机语言中添加某种语法,
这种语法能使程序员更方便的使用语言开发程序,
同时增强程序代码的可读性,避免出错的机会;但是这种语法对语言的功能并没有影响。
- 1
例如,泛型它就是一种语法糖,即使不用泛型,也能开发出同等功能的程序,例如排序算法,我可以分别实现Double、Int等类型的排序算法,但是我们使用泛型之后,可以大大简化程序设计,减少重复代码的编写,代码可读性也有所增加。
1. 中置类型(Infix Type)
在Scala中存在着中置操作符,如1+2等,+在这被称为中置操作符,前面我们说过,scala中的一切操作皆为对象调用,1+2其实是1.+(2)的对象方法调用。在scala中同样存在着中置类型,如:
class Person[T,S](val name:S,val age:T)object InfixType extends App {//下面的代码是一种中置表达方法,相当于//val p:Person[String,Int]=nullval p:String Person Int=null
}
- 2
可以看到,如果类的泛型参数是两个的话,则可以使用中置表达式进行变量的定义。中置类型最常用的场景是模式匹配,例如:
//定义Person类,两个泛型参数,分别是S,T,因此
//它是可以用中置表达式进行变量定义的
case class Person[S,T](val name:S,val age:T)object InfixType extends App {//下面的代码是一种中置表达方法,相当于//val p:Person[String,Int]val p:String Person Int= Person("摇摆少年梦",18)//中置表达式的模式匹配用法//模式匹配时可以直接用常量,也可以直接用变量p match {case "摇摆少年梦" Person 18=> println("matching is ok")case name Person age=> println("name:"+name+" age="+age) }
}
2. 存在类型
在看一些scala语言实现的框架或别人写的程序时,我们常常会发现下列形式定义的变量,例如:
object ExisitType extends App{//下面的Array[_]是一种存在类型,虽然用的是类型通配//符,但它本质上等同于//def print2(x:Array[T] forSome {type T})=println(x)//即Array[_]中的类型通匹符也是一种语法糖,用于简化设计def print(x:Array[_])=println(x)
}
更多的例子如:
object ExisitType extends App{def print(x:Array[_])=println(x)def print2(x:Array[T] forSome {type T})=println(x)//Map[_,_]相当于Map[T,U] forSome {type T;type U}def print3(x:Map[_,_])=println(x)print(Array("摇摆少年梦","学途无忧网金牌讲师"))print2(Array("摇摆少年梦","学途无忧网金牌讲师"))print3(Map("摇摆少年梦"->"学途无忧网金牌讲师"))
}
3. 函数类型
在scala中函数也是具有类型的,如下面的函数定义方式
//来自API文档中的例子,Function2
object Main extends App {//max与anonfun2是等价的,它们定义的都是输入参数是两个Int类型
//返回值也是Int类型的函数。
val max = (x: Int, y: Int) => if (x < y) y else x//通过Funtion2定义一个输入参数为两个整型
//返回类型为Int的函数,这里是通过new创建创建函数
//而这个类正是Function2,它是函数类型类
val anonfun2 = new Function2[Int, Int, Int] {def apply(x: Int, y: Int): Int = if (x < y) y else x
}
println(max(0, 1) == anonfun2(0, 1))
}
Function2对应的类型定义部分代码如下:
trait Function2[@specialized(scala.Int, scala.Long,
scala.Double) -T1, @specialized(scala.Int, scala.Long,
scala.Double) -T2, @specialized(scala.Unit,
scala.Boolean, scala.Int, scala.Float, scala.Long,scala.Double) +R] extends AnyRef
在scala中还存在单个参数的Function类型即Function1,它的类型定义部分代码如下:
@annotation.implicitNotFound
(msg = "No implicit view available from ${T1} => ${R}.")
trait Function1[@specialized(scala.Int,scala.Long, scala.Float, scala.Double/*,
(scala.Unit, scala.Boolean, scala.Int,scala.Float, scala.Long, scala.Double/*,scala.AnyRef*/) +R] extends AnyRef
下面的代码给出了它的用法:
object Main extends App {val succ = (x: Int) => x + 1
val anonfun1 = new Function1[Int, Int] {def apply(x: Int): Int = x + 1
}
//succ与anonfun1 函数是等价的,它们都定义了输入参数是Int
//返回值类型是Int的函数
assert(succ(0) == anonfun1(0))
}
通过Function1和Function2我们可以看到,其输入参数是逆变的,输出参数是协变的,我们可以通过下面的代码进行验证:
//代码给的是输出类型协变的替代使用
scala> class A; class B; class C extends B
defined class A
defined class B
defined class C
//定义一个输入类型是A,输出类型是C的函数字面量
scala> val x= (p:A)=>new C
x: A => C = <function1>//下面的代码定义了一个变量x2,它是一个函数类型
//该函数输入是A类型,输出是B类型
//由于B是C的超类,Function1的输出参数又是协变的
//因此下面的代码是合法的
scala> val x2:A=>B = x
x2: A => B = <function1>
//代码给的是输入类型是逆变的替代使用
class R; class X; class Y extends X
//创建输入类型是X类型,输出类型是R的函数字面量
val f1 = (x:X)=>new R
//下面的代码定义的变量f2是一个输入类型是Y,返回值类型是R
//的函数字面量,它被赋值为f1,由于输入类型是逆变的,也就是
//说Y是X的子类型,X=>R则是Y=>R的子类型,因此下面的代码是合法的
val f2:Y=>R = f1
4. 抽象类型
抽象类型是指在类或特质中利用type关键字定义一个没有确定类型的标识,该标识在子类中被确定,称这种类型为抽象类型,例如:
package cn.scala.xtwy.advancedtype//下面定义了一个抽象类
//抽象类中用type关键字声明了一个抽象类型IndentityType
abstract class Person1{type IdentityType//方法的返回值类型被声明为抽象类型def getIdentityNo():IdentityType
}
//在子类中,对抽象类型进行具体化
class Student extends Person1{//将抽象类型具体化为String类型type IdentityType=Stringdef getIdentityNo()="123"
}
class Teacher extends Person1{//将抽象类型具体化为Int类型type IdentityType=Intdef getIdentityNo()=123
}object AbstractType {def main(args: Array[String]): Unit = {//返回的是String类型println(new Student().getIdentityNo())}}
- 13
上述代码的也可用泛型进行实现,如:
//使用范型参数将方法的返回值定义为抽象类型
abstract class Person2[T]{def getIdentityNo():T
}
//子类带具体的类型String
class Student2 extends Person2[String]{def getIdentityNo():String="123"
}
//子类带具体的类型Int
class Teacher extends Person2[Int]{def getIdentityNo():Int=123
}
object AbstractType {def main(args: Array[String]): Unit = {//同样返回String类型println(new Student2().getIdentityNo())}}
- 6
在实际应用中,如果类型是在实例化的时候给定的,推荐用类型参数进行类的定义,例如经常需要用到new Person[String,Int](”摇摆少年梦”,18)这种创建对象的方式,此时使用泛型更为方便;如果类型是在子类型中才被确定,则推荐使用抽象类型。例如,从代码的简洁性方面考虑,下面的代码使用抽象类型的话更”省“
//下面是抽象类型的定义方式
trait Closable{type intype outdef close(x:in):out
}class File extends Closable{type in=Stringtype out=Booleandef close(x:in):out= true//....其它方法
}
- 3
下面的代码是类型参数的定义方式:
trait Closable[S,T]{def close(x:S):T
}class File extends Closable[String,Boolean]{def close(x:String):Boolean= true//....其它方法
}
当File类中还有大量的方法要用到String及Boolean类型时,抽象类型的优越性就能表现出来。
Scala入门到精通——第二十三节 高级类型 (二)相关推荐
- Scala入门到精通——第二十节 类型参数(二)
本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...
- Scala入门到精通——第二十四节 高级类型 (三)
本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...
- Scala入门到精通——第二十九节 Scala数据库编程
本节主要内容 Scala Mavenproject的创建 Scala JDBC方式訪问MySQL Slick简单介绍 Slick数据库编程实战 SQL与Slick相互转换 本课程在多数内容是在官方教程 ...
- Scala入门到精通——第二十八节 Scala与JAVA互操作
本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接 ...
- Scala入门到精通——第二十六节 Scala并发编程基础
本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 1. Scala并发编程简介 2003 年,Herb Sutte ...
- Scala入门到精通——第二十五节 提取器(Extractor)
本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...
- Scala入门到精通——第十三节 高阶函数
本节主要内容 高阶函数简介 Scala中的常用高阶函数 SAM转换 函数柯里化 部分应用函数 1. 高阶函数简介 高阶函数主要有两种:一种是将一个函数当做另外一个函数的参数(即函数参数):另外一种是返 ...
- Scala入门到精通——第二十二节 高级类型 (一)
本节主要内容 this.type使用 类型投影 结构类型 复合类型 1. this.type使用 class Person{private var name:String=nullprivate va ...
- Scala入门到精通——第十九节 隐式转换与隐式参数(二)
本节主要内容 隐式参数中的隐式转换 函数中隐式参数使用概要 隐式转换问题梳理 1. 隐式参数中的隐式转换 前一讲中,我们提到函数中如果存在隐式参数,在使用该函数的时候如果不给定对应的参数,则编译器会自 ...
最新文章
- vue-router学习笔记
- 算法-判断一颗树是否是搜索二叉树
- SpringBoot报错:Could not autowire. No beans of ‘DiscussantMapper‘ type found
- 掌门教育微服务体系 Solar | 阿里巴巴 Nacos 企业级落地上篇
- 冬天到了:你检查过你的防冻液了吗!
- 8_18 比赛总结 [暑假集训]
- SAP ABAP Netweaver容器化, 不可能完成的任务吗?
- 然爸读书笔记(2014-2)----影响力
- python数据分析基础教程 numpy_Python数据分析基础教程:NumPy学习指南(第2版)
- python len函数_Python 初学者必备的常用内置函数
- 数据-第11课-双向链表
- 环境监测设备中,使用GPS模拟器测试TTFF和灵敏度的注意点
- 数据结构中的英文及算法缩写
- python簇状柱形图_think-cell chart系列13——簇状堆积柱形图
- 【imx6ul】从头搭建imx6ul开发环境(uboot、内核编译及烧入、mfgtools详细使用方法)
- 四、PHP进阶学习之MySQL②
- 博客已死?移动互联网时代博客的价值
- Appium+Pytest+Allure集成PO项目管理模式实现自动化测试
- Hack The Box - Access Writeup
- MYSQL内存请求一直不释放_MySQL内存不释放分析
热门文章
- 【终极办法】Client does not support authentication protocol requested by server; consider upgrading mysql
- 风险评估资产重要性识别_如何有效的进行风险评估?
- access课程均不及格_access 第二章 查询 练习题 -
- java 命令读取参数_如何读取/处理命令行参数?
- python使用异常的目的和好处_python 错误与异常,python assert的作用
- homepage php,HomePage.php
- oracle中的greatest,ORACLE 内置函数之 GREATEST 和 LEAST(转)
- 使用计算机的优点缺点,计算机使用二进制的优缺点
- Java根据学号提取班级_学生成绩管理系统 1. 能够实现根据以下关键字查询:学生姓名 、学号、班级、课 联合开发网 - pudn.com...
- c 和java通讯大小端问题处理_记录一个如何解决java与C++socket通信的大小端问题...