scala的泛型

69 阅读4分钟

1. 基本泛型语法

1.1 泛型类

// 定义泛型类
class Box[T](value: T) {
  def getValue: T = value
  def setValue(newValue: T): Box[T] = new Box(newValue)
}

// 使用
val intBox = new Box[Int](42)
val stringBox = new Box[String]("Hello")
println(intBox.getValue)    // 42
println(stringBox.getValue) // Hello

1.2 泛型方法

// 泛型方法
def printElement[T](element: T): Unit = {
  println(s"元素: $element")
}

def swap[T](a: T, b: T): (T, T) = (b, a)

// 使用
printElement(100)          // 元素: 100
printElement("Scala")      // 元素: Scala
println(swap(1, 2))        // (2, 1)
println(swap("A", "B"))    // (B, A)

2. 类型参数约束

2.1 上界约束(<:)

// 定义类层次结构
abstract class Animal {
  def name: String
}

class Dog(val name: String) extends Animal
class Cat(val name: String) extends Animal
class Car(val model: String) // 不是Animal子类

// 上界约束:T必须是Animal或其子类
class AnimalShelter[T <: Animal](animal: T) {
  def showAnimal: String = s"收容所动物: ${animal.name}"
}

// 使用
val dogShelter = new AnimalShelter(new Dog("Buddy"))
val catShelter = new AnimalShelter(new Cat("Whiskers"))
// val carShelter = new AnimalShelter(new Car("Tesla")) // 编译错误

2.2 下界约束(>:)

// 下界约束:T必须是Animal或其父类
def addToGroup[T >: Dog](animal: T, group: List[T]): List[T] = animal :: group

val dogs: List[Dog] = List(new Dog("Buddy"), new Dog("Max"))
val animals: List[Animal] = List(new Dog("Buddy"), new Cat("Whiskers"))

addToGroup(new Dog("NewDog"), dogs)       // 可以
addToGroup(new Dog("NewDog"), animals)    // 可以

2.3 视图界定(<%)- Scala 2.x特性(Scala 3中已移除)

// Scala 2.x中的视图界定
def printValue[T <% Comparable[T]](value: T): Unit = {
  println(value)
}

2.4 上下文界定(:)

// 定义类型类
trait Show[T] {
  def show(t: T): String
}

// 定义隐式实例
implicit val intShow: Show[Int] = new Show[Int] {
  def show(t: Int): String = s"Int: $t"
}

implicit val stringShow: Show[String] = new Show[String] {
  def show(t: String): String = s"String: '$t'"
}

// 上下文界定:要求存在隐式的Show[T]实例
def printValue[T: Show](value: T): Unit = {
  val showInstance = implicitly[Show[T]]
  println(showInstance.show(value))
}

// 使用
printValue(42)      // Int: 42
printValue("Hello") // String: 'Hello'

3. 协变和逆变

3.1 协变(+)

// 协变:如果B是A的子类,那么Container[B]是Container[A]的子类
class Container[+T](value: T) {
  def get: T = value
  // def set(newValue: T): Unit = {} // 协变类型不能出现在方法参数位置
}

class Animal
class Dog extends Animal

val dogContainer: Container[Dog] = new Container(new Dog)
val animalContainer: Container[Animal] = dogContainer // 协变允许向上转型

3.2 逆变(-)

// 逆变:如果B是A的子类,那么Container[B]是Container[A]的父类
trait Printer[-T] {
  def print(value: T): Unit
}

class AnimalPrinter extends Printer[Animal] {
  def print(animal: Animal): Unit = println(s"Animal: $animal")
}

class DogPrinter extends Printer[Dog] {
  def print(dog: Dog): Unit = println(s"Dog: $dog")
}

// 逆变允许向下转型
val dogPrinter: Printer[Dog] = new AnimalPrinter
dogPrinter.print(new Dog) // 可以,AnimalPrinter可以处理Dog

4. 类型通配符

class Animal
class Dog extends Animal
class Cat extends Animal

// 使用通配符
def processAnimals(animals: List[_ <: Animal]): Unit = {
  animals.foreach(animal => println(animal))
}

def addAnimal(animals: List[_ >: Dog]): List[Any] = {
  new Dog("NewDog") :: animals
}

val dogs: List[Dog] = List(new Dog, new Dog)
val animals: List[Animal] = List(new Dog, new Cat)

processAnimals(dogs)      // 可以
processAnimals(animals)   // 可以

addAnimal(dogs)           // 可以
addAnimal(animals)        // 可以

5. 泛型实战示例

5.1 泛型栈实现

class Stack[T] {
  private var elements: List[T] = Nil
  
  def push(element: T): Unit = {
    elements = element :: elements
  }
  
  def pop(): Option[T] = elements match {
    case Nil => None
    case head :: tail => 
      elements = tail
      Some(head)
  }
  
  def peek: Option[T] = elements.headOption
  
  def isEmpty: Boolean = elements.isEmpty
  
  def size: Int = elements.length
}

// 使用
val intStack = new Stack[Int]
intStack.push(1)
intStack.push(2)
println(intStack.pop()) // Some(2)

val stringStack = new Stack[String]
stringStack.push("Hello")
stringStack.push("World")

5.2 泛型Pair类

case class Pair[A, B](first: A, second: B) {
  def swap: Pair[B, A] = Pair(second, first)
  
  def mapFirst[C](f: A => C): Pair[C, B] = Pair(f(first), second)
  
  def mapSecond[C](f: B => C): Pair[A, C] = Pair(first, f(second))
}

// 使用
val pair1 = Pair(42, "Answer")
val pair2 = pair1.swap // Pair("Answer", 42)
val pair3 = pair1.mapFirst(_ * 2) // Pair(84, "Answer")

5.3 泛型排序函数

// 使用Ordering上下文界定
def bubbleSort[T : Ordering](arr: Array[T]): Array[T] = {
  val ord = implicitly[Ordering[T]]
  val sorted = arr.clone()
  
  for (i <- 0 until sorted.length) {
    for (j <- 0 until sorted.length - i - 1) {
      if (ord.gt(sorted(j), sorted(j + 1))) {
        val temp = sorted(j)
        sorted(j) = sorted(j + 1)
        sorted(j + 1) = temp
      }
    }
  }
  sorted
}

// 使用
val intArray = Array(5, 3, 8, 1, 2)
println(bubbleSort(intArray).mkString(", ")) // 1, 2, 3, 5, 8

val stringArray = Array("banana", "apple", "cherry")
println(bubbleSort(stringArray).mkString(", ")) // apple, banana, cherry

6. 高级泛型特性

6.1 类型别名

type StringMap[V] = Map[String, V]
type IntList = List[Int]
type OptionList[T] = List[Option[T]]

// 使用
val scores: StringMap[Int] = Map("Alice" -> 95, "Bob" -> 87)

6.2 抽象类型成员

trait Container {
  type T
  def value: T
  def setValue(newValue: T): Unit
}

class IntContainer extends Container {
  type T = Int
  private var _value: Int = 0
  def value: Int = _value
  def setValue(newValue: Int): Unit = _value = newValue
}

6.3 路径依赖类型

class Outer {
  class Inner
  def createInner: Inner = new Inner
}

val outer1 = new Outer
val outer2 = new Outer

val inner1: outer1.Inner = outer1.createInner
val inner2: outer2.Inner = outer2.createInner
// val inner3: outer1.Inner = outer2.createInner // 编译错误,类型不匹配

7. 最佳实践

  1. 命名约定:通常使用单个大写字母作为类型参数名

    • T:类型(Type)
    • A, B:任意类型
    • E:元素(Element)
    • K:键(Key)
    • V:值(Value)
  2. 限制泛型使用:只在真正需要的地方使用泛型

  3. 优先使用上下文界定:而不是视图界定(Scala 2.x)或隐式参数

  4. 考虑协变/逆变:设计API时考虑类型变体的需求

  5. 文档化约束:为复杂的泛型约束添加注释说明

8. Scala 3中的新特性

Scala 3引入了更强大的泛型特性:

// 交集类型
type Worker = Employee & Programmer

// 并集类型
type Id = Int | String

// 匹配类型
type ElemType[X] = X match {
  case List[t] => t
  case Array[t] => t
  case _ => X
}