1.6. 类型系统
Scala 拥有强大的静态类型系统,能够在不牺牲表达能力的前提下提供类型安全。
1.6.1. 泛型
泛型允许定义适用于多种类型的类、特质和方法:
// 泛型类
class Box[A](value: A):
def get: A = value
val intBox = Box(42)
val strBox = Box("Hello")
// 泛型方法
def identity[A](x: A): A = x
identity(42) // 推断为 Int
identity("Hello") // 推断为 String
1.6.1.1. 泛型约束
上界(Upper Bound):限定类型必须是某个类型的子类型:
// A 必须是 Ordered[A] 的子类型
def max[A <: Ordered[A]](a: A, b: A): A = if a >= b then a else b
下界(Lower Bound):限定类型必须是某个类型的父类型:
// B 必须是 A 的父类型
def coerce[A, B >: A](a: A): B = a
上下界可以结合使用:
// [A >: Low <: High]
1.6.2. 协变、逆变与不变
修饰符 |
名称 |
含义 |
示例 |
|---|---|---|---|
|
协变 |
|
|
|
逆变 |
|
|
|
不变 |
只能持有精确类型 |
|
class Animal
class Dog extends Animal
// 协变
val dogs: List[Dog] = List(Dog())
val animals: List[Animal] = dogs // OK
// 逆变:函数参数是逆变的
val f: Dog => Dog = identity
val g: Animal => Dog = f // OK(Animal => Dog 可替代 Dog => Dog)
示例:自定义协变容器:
sealed trait MyList[+A]:
def head: A
def tail: MyList[A]
def ::[B >: A](elem: B): MyList[B] = MyCons(elem, this)
case object MyNil extends MyList[Nothing]
case class MyCons[A](head: A, tail: MyList[A]) extends MyList[A]
1.6.3. 类型约束
1.6.3.1. 上下文界定(Context Bound)
// 要求存在 implicit/given Ordering[A]
def sort[A: Ordering](list: List[A]): List[A] =
list.sorted
1.6.3.2. 视图界定(View Bound,Scala 2 风格,Scala 3 中移除)
// Scala 2 写法(已废弃)
// def max[A <% Ordered[A]](a: A, b: A): A = ...
// Scala 3 使用 given/using 替代
def max[A](a: A, b: A)(using ord: Ordering[A]): A =
if ord.gteq(a, b) then a else b
1.6.4. 给定实例与 using 子句(Scala 3)
Scala 3 用 given / using 替代了 Scala 2 的 implicit:
// 定义给定实例
given intOrdering: Ordering[Int] with
def compare(x: Int, y: Int): Int = x - y
// 使用 given 实例的 using 子句
def maxList[A](list: List[A])(using ord: Ordering[A]): A =
list.max
// 调用时无需传入 using 参数(编译期自动解析)
maxList(List(3, 1, 4, 1, 5)) // 5
上下文参数简写:
def maxList[A: Ordering](list: List[A]): A =
// summon[Ordering[A]] 获取 given 实例
list.max
1.6.4.1. 类型类模式
类型类(Type Class)是 Scala 中的经典设计模式,结合了泛型和 given/using:
// 1. 定义类型类的 trait
trait Show[A]:
def show(a: A): String
// 2. 提供给定实例
given Show[Int] with
def show(a: Int): String = a.toString
given Show[String] with
def show(a: String): String = s""""$a""""
// 3. 使用类型类
def printShow[A](a: A)(using s: Show[A]): Unit =
println(s.show(a))
printShow(42) // 42
printShow("Hello") // "Hello"
1.6.5. 联合类型与交集类型(Scala 3)
1.6.5.1. 联合类型(Union Type)
表示值可以是多种类型之一:
type Result = Int | String
def handle(result: Result): String = result match
case i: Int => s"整数: $i"
case s: String => s"字符串: $s"
1.6.5.2. 交集类型(Intersection Type)
表示值必须同时满足多种类型:
trait Readable:
def read: String
trait Writable:
def write(data: String): Unit
def process(rw: Readable & Writable): Unit =
val data = rw.read
rw.write(data)
1.6.6. 不透明类型(Opaque Type)
不透明类型为现有类型提供类型安全的包装,运行时无开销:
object Domain:
opaque type UserId = Long
object UserId:
def apply(id: Long): UserId = id
extension (id: UserId) def value: Long = id
import Domain.UserId
val uid: UserId = UserId(42)
// val bad: Long = uid // 编译错误!不能在不透明类型定义域外解包