隐式转换 #

一、隐式转换概述 #

1.1 什么是隐式转换 #

隐式转换允许自动将一种类型转换为另一种类型,常用于:

  • 扩展现有类的功能
  • 类型适配
  • 提供默认值

1.2 Scala 2 vs Scala 3 #

Scala 2 Scala 3
implicit given / using
implicit class extension
implicit def given Conversion

二、隐式类(Scala 2) #

2.1 定义隐式类 #

scala
implicit class StringExtensions(val s: String) extends AnyVal:
  def greet: String = s"Hello, $s!"
  def shout: String = s.toUpperCase + "!"
  def repeat(n: Int): String = s * n

"Scala".greet
"hello".shout
"ab".repeat(3)

2.2 隐式类规则 #

  • 必须有且仅有一个参数
  • 不能是顶层类
  • 不能是 case class

2.3 扩展方法 #

scala
implicit class IntExtensions(val n: Int) extends AnyVal:
  def times(action: => Unit): Unit = (1 to n).foreach(_ => action)
  def isEven: Boolean = n % 2 == 0
  def isOdd: Boolean = n % 2 != 0

5.times(println("Hello"))
42.isEven

三、Extension 方法(Scala 3) #

3.1 定义扩展方法 #

scala
extension (s: String)
  def greet: String = s"Hello, $s!"
  def shout: String = s.toUpperCase + "!"
  def repeat(n: Int): String = s * n

"Scala".greet
"hello".shout
"ab".repeat(3)

3.2 泛型扩展方法 #

scala
extension [T](list: List[T])
  def second: Option[T] = list.drop(1).headOption
  def third: Option[T] = list.drop(2).headOption
  def takeWhileWithIndex(p: (T, Int) => Boolean): List[T] =
    list.zipWithIndex.takeWhile(p.tupled).map(_._1)

List(1, 2, 3, 4, 5).second
List("a", "b", "c").third

3.3 扩展方法组织 #

scala
object StringExtensions:
  extension (s: String)
    def greet: String = s"Hello, $s!"
    def shout: String = s.toUpperCase + "!"

import StringExtensions.*

"Scala".greet

四、Given 和 Using(Scala 3) #

4.1 定义 Given #

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

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

4.2 使用 Given #

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

printShow(42)
printShow("hello")
printShow(true)

4.3 匿名 Given #

scala
given ordering: Ordering[Person] = Ordering.by(_.age)

given Show[Int] = _.toString

4.4 Given 导入 #

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

import ShowInstances.given

printShow(42)

五、隐式转换函数 #

5.1 Scala 2 隐式转换 #

scala
implicit def intToString(n: Int): String = n.toString

val s: String = 42

5.2 Scala 3 Conversion #

scala
given Conversion[Int, String] = _.toString

val s: String = 42

5.3 自定义转换 #

scala
case class Meter(value: Double)
case class Kilometer(value: Double)

given Conversion[Meter, Kilometer] = m => Kilometer(m.value / 1000)
given Conversion[Kilometer, Meter] = km => Meter(km.value * 1000)

val m = Meter(1000)
val km: Kilometer = m
println(km)

六、隐式参数 #

6.1 定义隐式参数 #

scala
trait Config:
  def host: String
  def port: Int

def connect()(using config: Config): Connection =
  ???

given Config with
  def host: String = "localhost"
  def port: Int = 8080

connect()

6.2 多个隐式参数 #

scala
trait Logger:
  def log(message: String): Unit

trait Database:
  def query(sql: String): Result

def processData()(using logger: Logger, db: Database): Unit =
  logger.log("Processing data")
  db.query("SELECT * FROM data")

given Logger with
  def log(message: String): Unit = println(s"[LOG] $message")

given Database with
  def query(sql: String): Result = ???

processData()

6.3 隐式参数默认值 #

scala
def greet(name: String)(using greeting: String = "Hello"): String =
  s"$greeting, $name!"

greet("Alice")
greet("Bob")(using "Hi")

七、类型类模式 #

7.1 定义类型类 #

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](using writer: JsonWriter[T]): JsonWriter[List[T]] with
    def write(value: List[T]): String =
      value.map(writer.write).mkString("[", ", ", "]")
  
  given [K, V](using keyWriter: JsonWriter[K], valueWriter: JsonWriter[V]): JsonWriter[Map[K, V]] with
    def write(value: Map[K, V]): String =
      value.map { case (k, v) => s"${keyWriter.write(k)}: ${valueWriter.write(v)}" }
        .mkString("{", ", ", "}")

7.2 使用类型类 #

scala
def toJson[T](value: T)(using writer: JsonWriter[T]): String =
  writer.write(value)

import JsonWriter.given

toJson(42)
toJson("hello")
toJson(List(1, 2, 3))
toJson(Map("a" -> 1, "b" -> 2))

7.3 类型类扩展 #

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

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

toJson(Person("Alice", 25))

八、隐式解析规则 #

8.1 查找顺序 #

  1. 当前作用域
  2. 导入的隐式值
  3. 伴生对象中的隐式值
  4. 外部作用域

8.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})"

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

printShow(Person("Alice", 25))

九、最佳实践 #

9.1 使用 extension 替代 implicit class #

scala
extension (s: String)
  def greet: String = s"Hello, $s!"

9.2 使用 given/using 替代 implicit #

scala
given Show[Int] = _.toString

def show[T](value: T)(using s: Show[T]): String = s.show(value)

9.3 类型类放在伴生对象中 #

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

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

9.4 避免隐式转换滥用 #

scala
given Conversion[String, Int] = _.length

val n: Int = "hello"

十、总结 #

Scala 3 隐式语法 #

概念 语法
定义隐式值 given Name: Type = value
定义隐式参数 using param: Type
扩展方法 extension (x: T) def method
类型转换 given Conversion[A, B]

类型类模式 #

组件 说明
Trait 定义行为接口
Given 提供具体实现
Using 使用隐式值

下一步,让我们学习 上下文界定

最后更新:2026-03-27