上下文界定 #
一、上下文界定概述 #
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