Scala教程之:静态类型 (一)

简介: Scala教程之:静态类型 (一)

文章目录



Scala是静态类型的,它拥有一个强大的类型系统,静态地强制以安全、一致的方式使用抽象,我们通过下面几个特征来一一说明:


  • 泛类型
  • 型变
  • 类型上界
  • 类型下界
  • 内部类
  • 抽象类型
  • 复合类型
  • 自类型
  • 隐式参数
  • 隐式转换
  • 多态方法
  • 类型推断


通过这些特性,为安全可重用的编程抽象以及类型安全的扩展提供了强大的基础。


泛类型


和java一样,Scala也有泛型的概念,在scala里面泛型是使用方括号 [] 来接受类型参数的。通常使用字母A来作为参数标志符,当然你也可以使用其他任意的参数名称。


class Stack[A] {
  private var elements: List[A] = Nil
  def push(x: A) { elements = x :: elements }
  def peek: A = elements.head
  def pop(): A = {
    val currentTop = peek
    elements = elements.tail
    currentTop
  }
}


要使用一个泛类型,将一个具体的类型替换掉A即可。


val stack = new Stack[Int]
stack.push(1)
stack.push(2)
println(stack.pop)  // prints 2
println(stack.pop)  // prints 1


上面的例子中,实例对象接收整型值,如果该类型有子类型,子类型也是可以传入的。


class Fruit
class Apple extends Fruit
class Banana extends Fruit
val stack = new Stack[Fruit]
val apple = new Apple
val banana = new Banana
stack.push(apple)
stack.push(banana)


型变


型变主要是针对泛类型来说的,用来表示这种复杂类型的相关性。型变主要有协变,逆变和不变三种情况。在类型系统中使用型变允许我们在复杂类型之间建立直观的连接,而缺乏型变则会限制类抽象的重用性。


class Foo[+A] // A covariant class
class Bar[-A] // A contravariant class
class Baz[A]  // An invariant class


协变


协变使用+A来表示。对于某些类 class List[+A],使 A 成为协变意味着对于两种类型 C 和 D,如果 C 是 D 的子类型,那么 List[C] 就是 List[D] 的子类型。 这允许我们使用泛型来创建非常有用和直观的子类型关系。


abstract class Animal {
  def name: String
}
case class Cat(name: String) extends Animal
case class Dog(name: String) extends Animal


上面的例子中类型 Cat 和 Dog 都是 Animal 的子类型。那么

List[Cat]和List[Dog]都是List[Animal]的子类。


下面看下协变的应用:


object CovarianceTest extends App {
  def printAnimalNames(animals: List[Animal]): Unit = {
    animals.foreach { animal =>
      println(animal.name)
    }
  }
  val cats: List[Cat] = List(Cat("Whiskers"), Cat("Tom"))
  val dogs: List[Dog] = List(Dog("Fido"), Dog("Rex"))
  printAnimalNames(cats)
  // Whiskers
  // Tom
  printAnimalNames(dogs)
  // Fido
  // Rex
}


在上面的例子中,方法 printAnimalNames 将接受动物列表作为参数,并且逐行打印出它们的名称。 如果 List[A] 不是协变的,最后两个方法调用将不能编译,这将严重限制 printAnimalNames 方法的适用性。


逆变


逆变和协变相反,使用-A来表示。对于某个类 class Writer[-A] ,使 A 逆变意味着对于两种类型 C 和 D,如果 C 是 D 的子类型,那么 Writer[D] 是 Writer[C] 的子类型。

考虑一下的例子:


abstract class Printer[-A] {
  def print(value: A): Unit
}


我们定义两个printer:


class AnimalPrinter extends Printer[Animal] {
  def print(animal: Animal): Unit =
    println("The animal's name is: " + animal.name)
}
class CatPrinter extends Printer[Cat] {
  def print(cat: Cat): Unit =
    println("The cat's name is: " + cat.name)
}


如果 Printer[Cat] 知道如何在控制台打印出任意 Cat,并且 Printer[Animal] 知道如何在控制台打印出任意 Animal,那么 Printer[Animal] 也应该知道如何打印出 Cat 就是合理的。 反向关系不适用,因为 Printer[Cat] 并不知道如何在控制台打印出任意 Animal。 因此,如果我们愿意,我们应该能够用 Printer[Animal] 替换 Printer[Cat],而使 Printer[A] 逆变允许我们做到这一点。


object ContravarianceTest extends App {
  val myCat: Cat = Cat("Boots")
  def printMyCat(printer: Printer[Cat]): Unit = {
    printer.print(myCat)
  }
  val catPrinter: Printer[Cat] = new CatPrinter
  val animalPrinter: Printer[Animal] = new AnimalPrinter
  printMyCat(catPrinter)
  printMyCat(animalPrinter)
}


不变


默认情况下,Scala中的泛型类是不变的。这意味着虽然Cat是Animal的子类,但是Container[Cat]和Container[Animal]之间没有任何关系。


相关文章
|
1月前
|
Java Scala
Scala 教程
Scala 教程
31 2
|
7月前
|
IDE Java 编译器
scala的两种变量类型 var 和 val
scala的两种变量类型 var 和 val
159 2
scala的两种变量类型 var 和 val
|
安全 Java 大数据
大数据开发基础的编程语言的Scala的类型系统
Scala是一种强类型的编程语言,它具有一套完善的类型系统。本文将介绍Scala的类型系统,帮助开发者了解这门语言的类型安全性和灵活性。
100 0
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
121 0
一天学完spark的Scala基础语法教程十三、文件IO操作(idea版本)
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
204 0
一天学完spark的Scala基础语法教程十二、异常处理(idea版本)
|
分布式计算 Java Scala
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
167 0
一天学完spark的Scala基础语法教程十一、正则表达式(idea版本)
|
存储 分布式计算 Java
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
132 0
一天学完spark的Scala基础语法教程十、类和对象(idea版本)
|
分布式计算 Scala Spark
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
138 0
一天学完spark的Scala基础语法教程九、迭代器(idea版本)
|
分布式计算 Scala Spark
一天学完spark的Scala基础语法教程八、集合(idea版本)
一天学完spark的Scala基础语法教程八、集合(idea版本)
152 0
一天学完spark的Scala基础语法教程八、集合(idea版本)
|
大数据 Java 编译器
Scala 字符类型|学习笔记
快速学习 Scala 字符类型。
182 0