本节主要内容
- 中置类型(Infix Type)
- 存在类型
- 函数类型
- 抽象类型
关于语法糖的问题,在讲解程序语言时,我们常常听到“语法糖”这个术语,在百度百科中,它具有如下定义:
语法糖(Syntactic Sugar),也叫糖衣语法,
是英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语。
指的是,在计算机语言中添加某种语法,
种语法能使程序员更方便的使用语言开发程序,
同时增强程序代码的可读性,避免出错的机会;但是这种语法对语言的功能并没有影响。
例如,泛型它就是一种语法糖,即使不用泛型,也能开发出同等功能的程序,例如排序算法,我可以分别实现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:String Person Int=null
}
可以看到,如果类的泛型参数是两个的话,则可以使用中置表达式进行变量的定义。中置类型最常用的场景是模式匹配,例如:
case class Person[S,T](val name:S,val age:T)
object InfixType extends App {
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{
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)
def print3(x:Map[_,_])=println(x)
print(Array("摇摆少年梦","学途无忧网金牌讲师"))
print2(Array("摇摆少年梦","学途无忧网金牌讲师"))
print3(Map("摇摆少年梦"->"学途无忧网金牌讲师"))
}
3. 函数类型
本小节中的部分代码来自:http://hongjiang.info/scala-function-polymorphic/,感谢作者的无私奉献
在scala中函数也是具有类型的,如下面的函数定义方式
object Main extends App {
val max = (x: Int, y: Int) => if (x < y) y else x
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
}
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
scala> val x= (p:A)=>new C
x: A => C = <function1>
scala> val x2:A=>B = x
x2: A => B = <function1>
class R; class X; class Y extends X
val f1 = (x:X)=>new R
val f2:Y=>R = f1
4. 抽象类型
抽象类型是指在类或特质中利用type关键字定义一个没有确定类型的标识,该标识在子类中被确定,称这种类型为抽象类型,例如:
package cn.scala.xtwy.advancedtype
abstract class Person1{
type IdentityType
def getIdentityNo():IdentityType
}
class Student extends Person1{
type IdentityType=String
def getIdentityNo()="123"
}
class Teacher extends Person1{
type IdentityType=Int
def getIdentityNo()=123
}
object AbstractType {
def main(args: Array[String]): Unit = {
println(new Student().getIdentityNo())
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
上述代码的也可用泛型进行实现,如:
abstract class Person2[T]{
def getIdentityNo():T
}
class Student2 extends Person2[String]{
def getIdentityNo():String="123"
}
class Teacher extends Person2[Int]{
def getIdentityNo():Int=123
}
object AbstractType {
def main(args: Array[String]): Unit = {
println(new Student2().getIdentityNo())
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
在实际应用中,如果类型是在实例化的时候给定的,推荐用类型参数进行类的定义,例如经常需要用到new Person[String,Int](”摇摆少年梦”,18)这种创建对象的方式,此时使用泛型更为方便;如果类型是在子类型中才被确定,则推荐使用抽象类型。例如,从代码的简洁性方面考虑,下面的代码使用抽象类型的话更”省“
//下面是抽象类型的定义方式
trait Closable{
type in
type out
def close(x:in):out
}
class File extends Closable{
type in=String
type out=Boolean
def close(x:in):out= true
}
下面的代码是类型参数的定义方式:
trait Closable[S,T]{
def close(x:S):T
}
class File extends Closable[String,Boolean]{
def close(x:String):Boolean= true
}
当File类中还有大量的方法要用到String及Boolean类型时,抽象类型的优越性就能表现出来。