本节主要内容

  1. 中置类型(Infix Type)
  2. 存在类型
  3. 函数类型
  4. 抽象类型

关于语法糖的问题,在讲解程序语言时,我们常常听到“语法糖”这个术语,在百度百科中,它具有如下定义:

语法糖(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入门到精通——第二十三节 高级类型 (二)相关推荐

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

    本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对Scala中的 ...

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

    本节主要内容 Type Specialization Manifest.TypeTag.ClassTag Scala类型系统总结 在Scala中,类(class)与类型(type)是两个不一样的概念. ...

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

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

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

    本节主要内容 JAVA中调用Scala类 Scala中调用JAVA类 Scala类型参数与JAVA泛型互操作 Scala与Java间的异常处理互操作 1. JAVA中调用Scala类 Java可以直接 ...

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

    本节主要内容 Scala并发编程简介 Scala Actor并发编程模型 react模型 Actor的几种状态 Actor深入使用解析 1. Scala并发编程简介 2003 年,Herb Sutte ...

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

    本节主要内容 apply与unapply方法 零变量或变量的模式匹配 提取器与序列模式 scala中的占位符使用总结 1. apply与unapply方法 apply方法我们已经非常熟悉了,它帮助我们 ...

  7. Scala入门到精通——第十三节 高阶函数

    本节主要内容 高阶函数简介 Scala中的常用高阶函数 SAM转换 函数柯里化 部分应用函数 1. 高阶函数简介 高阶函数主要有两种:一种是将一个函数当做另外一个函数的参数(即函数参数):另外一种是返 ...

  8. Scala入门到精通——第二十二节 高级类型 (一)

    本节主要内容 this.type使用 类型投影 结构类型 复合类型 1. this.type使用 class Person{private var name:String=nullprivate va ...

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

    本节主要内容 隐式参数中的隐式转换 函数中隐式参数使用概要 隐式转换问题梳理 1. 隐式参数中的隐式转换 前一讲中,我们提到函数中如果存在隐式参数,在使用该函数的时候如果不给定对应的参数,则编译器会自 ...

最新文章

  1. vue-router学习笔记
  2. 算法-判断一颗树是否是搜索二叉树
  3. SpringBoot报错:Could not autowire. No beans of ‘DiscussantMapper‘ type found
  4. 掌门教育微服务体系 Solar | 阿里巴巴 Nacos 企业级落地上篇
  5. 冬天到了:你检查过你的防冻液了吗!
  6. 8_18 比赛总结 [暑假集训]
  7. SAP ABAP Netweaver容器化, 不可能完成的任务吗?
  8. 然爸读书笔记(2014-2)----影响力
  9. python数据分析基础教程 numpy_Python数据分析基础教程:NumPy学习指南(第2版)
  10. python len函数_Python 初学者必备的常用内置函数
  11. 数据-第11课-双向链表
  12. 环境监测设备中,使用GPS模拟器测试TTFF和灵敏度的注意点
  13. 数据结构中的英文及算法缩写
  14. python簇状柱形图_think-cell chart系列13——簇状堆积柱形图
  15. 【imx6ul】从头搭建imx6ul开发环境(uboot、内核编译及烧入、mfgtools详细使用方法)
  16. 四、PHP进阶学习之MySQL②
  17. 博客已死?移动互联网时代博客的价值
  18. Appium+Pytest+Allure集成PO项目管理模式实现自动化测试
  19. Hack The Box - Access Writeup
  20. MYSQL内存请求一直不释放_MySQL内存不释放分析

热门文章

  1. 【终极办法】Client does not support authentication protocol requested by server; consider upgrading mysql
  2. 风险评估资产重要性识别_如何有效的进行风险评估?
  3. access课程均不及格_access 第二章 查询 练习题 -
  4. java 命令读取参数_如何读取/处理命令行参数?
  5. python使用异常的目的和好处_python 错误与异常,python assert的作用
  6. homepage php,HomePage.php
  7. oracle中的greatest,ORACLE 内置函数之 GREATEST 和 LEAST(转)
  8. 使用计算机的优点缺点,计算机使用二进制的优缺点
  9. Java根据学号提取班级_学生成绩管理系统 1. 能够实现根据以下关键字查询:学生姓名 、学号、班级、课 联合开发网 - pudn.com...
  10. c 和java通讯大小端问题处理_记录一个如何解决java与C++socket通信的大小端问题...