上下文界定 #

一、上下文界定概述 #

1.1 什么是上下文界定 #

上下文界定(Context Bounds)是一种简化的隐式参数语法,用于要求存在某个类型的隐式值。

1.2 语法对比 #

完整语法:

scala
def max[T](a: T, b: T)(using ord: Ordering[T]): T =
  if ord.compare(a, b) > 0 then a else b

上下文界定语法:

scala
def max[T: Ordering](a: T, b: T): T =
  val ord = summon[Ordering[T]]
  if ord.compare(a, b) > 0 then a else b

二、上下文界定使用 #

2.1 基本用法 #

scala
def sort[T: Ordering](list: List[T]): List[T] =
  list.sorted

def max[T: Ordering](a: T, b: T): T =
  if summon[Ordering[T]].compare(a, b) > 0 then a else b

sort(List(3, 1, 4, 1, 5))
max("hello", "world")

2.2 获取隐式值 #

使用 summon 获取隐式值:

scala
def process[T: Show](value: T): String =
  summon[Show[T]].show(value)

2.3 多个上下文界定 #

scala
def process[T: Ordering: Show](value: T): String =
  val show = summon[Show[T]]
  val ord = summon[Ordering[T]]
  show.show(value)

三、类型类模式 #

3.1 定义类型类 #

scala
trait Show[T]:
  def show(value: T): String

trait Eq[T]:
  def eqv(a: T, b: T): Boolean

trait Monoid[T]:
  def empty: T
  def combine(a: T, b: T): T

3.2 实现类型类实例 #

scala
given Show[Int] with
  def show(value: Int): String = value.toString

given Show[String] with
  def show(value: String): String = value

given Show[Boolean] with
  def show(value: Boolean): String = value.toString

given Monoid[Int] with
  def empty: Int = 0
  def combine(a: Int, b: Int): Int = a + b

given Monoid[String] with
  def empty: String = ""
  def combine(a: String, b: String): String = a + b

3.3 使用类型类 #

scala
def printShow[T: Show](value: T): Unit =
  println(summon[Show[T]].show(value))

def combineAll[T: Monoid](list: List[T]): T =
  list.foldLeft(summon[Monoid[T]].empty)(summon[Monoid[T]].combine)

printShow(42)
printShow("hello")
combineAll(List(1, 2, 3, 4, 5))
combineAll(List("a", "b", "c"))

四、视图界定(已弃用) #

4.1 Scala 2 视图界定 #

scala
def max[T <% Ordered[T]](a: T, b: T): T =
  if a > b then a else b

4.2 Scala 3 替代方案 #

使用上下文界定:

scala
def max[T: Ordering](a: T, b: T): T =
  val ord = summon[Ordering[T]]
  if ord.compare(a, b) > 0 then a else b

或使用隐式转换:

scala
def max[T](a: T, b: T)(using ord: Ordering[T]): T =
  given Conversion[T, Ordered[T]] = x => Ordered.orderingToOrdered(x)
  if a > b then a else b

五、类型约束 #

5.1 类型关系约束 #

scala
def firstOf[A, B <: A](list: List[B]): Option[A] =
  list.headOption

def addTo[A, B >: A](list: List[A], item: B): List[B] =
  item :: list

5.2 类型类约束 #

scala
trait Comparable[T]:
  def compare(a: T, b: T): Int

def max[T](a: T, b: T)(using comp: Comparable[T]): T =
  if comp.compare(a, b) > 0 then a else b

5.3 多重约束 #

scala
def process[T: Show: Ordering](value: T, other: T): String =
  val show = summon[Show[T]]
  val ord = summon[Ordering[T]]
  val comparison = ord.compare(value, other)
  s"${show.show(value)} vs ${show.show(other)}: $comparison"

六、实战示例 #

6.1 JSON 序列化 #

scala
trait JsonWriter[T]:
  def write(value: T): String

object JsonWriter:
  given JsonWriter[Int] with
    def write(value: Int): String = value.toString
  
  given JsonWriter[String] with
    def write(value: String): String = s""""$value""""
  
  given JsonWriter[Boolean] with
    def write(value: Boolean): String = value.toString
  
  given [T: JsonWriter]: JsonWriter[List[T]] with
    def write(value: List[T]): String =
      value.map(summon[JsonWriter[T]].write).mkString("[", ", ", "]")
  
  given [T: JsonWriter]: JsonWriter[Option[T]] with
    def write(value: Option[T]): String =
      value.map(summon[JsonWriter[T]].write).getOrElse("null")

def toJson[T: JsonWriter](value: T): String =
  summon[JsonWriter[T]].write(value)

import JsonWriter.given

toJson(42)
toJson("hello")
toJson(List(1, 2, 3))
toJson(Option("value"))

6.2 数据库访问 #

scala
trait Database[T]:
  def findById(id: Long): Option[T]
  def save(entity: T): T
  def delete(id: Long): Unit

def withEntity[T: Database, R](id: Long)(f: T => R): Option[R] =
  summon[Database[T]].findById(id).map(f)

given Database[User] with
  def findById(id: Long): Option[User] = ???
  def save(entity: User): User = ???
  def delete(id: Long): Unit = ???

withEntity[User, String](1L)(_.name)

6.3 配置管理 #

scala
trait ConfigReader[T]:
  def read(value: String): Option[T]

object ConfigReader:
  given ConfigReader[Int] with
    def read(value: String): Option[Int] = value.toIntOption
  
  given ConfigReader[String] with
    def read(value: String): Option[String] = Some(value)
  
  given ConfigReader[Boolean] with
    def read(value: String): Option[Boolean] =
      value.toLowerCase match
        case "true" | "yes" | "1" => Some(true)
        case "false" | "no" | "0" => Some(false)
        case _ => None

def getConfig[T: ConfigReader](key: String)(using map: Map[String, String]): Option[T] =
  map.get(key).flatMap(summon[ConfigReader[T]].read)

given Map[String, String] = Map(
  "port" -> "8080",
  "host" -> "localhost",
  "debug" -> "true"
)

getConfig[Int]("port")
getConfig[String]("host")
getConfig[Boolean]("debug")

七、上下文界定最佳实践 #

7.1 使用 summon 获取隐式值 #

scala
def process[T: Show](value: T): String =
  summon[Show[T]].show(value)

7.2 类型类放在伴生对象 #

scala
case class Person(name: String, age: Int)

object Person:
  given Show[Person] with
    def show(value: Person): String = s"${value.name} (${value.age})"

7.3 使用扩展方法 #

scala
extension [T: Show](value: T)
  def show: String = summon[Show[T]].show(value)

42.show
"hello".show

八、总结 #

上下文界定语法 #

语法 说明
T: Context 要求存在 Context[T]
summon[Context[T]] 获取隐式值
T: A: B 多个上下文界定

类型类模式 #

组件 说明
Trait 定义行为
Given 提供实例
Using/Context Bounds 使用实例

下一步,让我们学习 类型系统

最后更新:2026-03-27