7Scala for the Impatient(第2版)

隐式与注解

高级特性

隐式参数隐式转换注解宏

🎯 AI 时代的学习建议:不要只读理论。理解这一章的设计动机(为什么需要这个概念?)和边界条件(什么情况下会失效?)。当 AI 生成的代码涉及这些概念时,你能判断它是否用对了场景。AI 能帮你总结内容,但无法替代你亲手阅读、思考、建立直觉的过程。

第7章:隐式与注解

一、导读

1.1 本章学习目标

第7章讲解 Scala 的高级特性:隐式参数、隐式转换、注解。

本章核心学习目标:

  • 掌握隐式参数:自动传递上下文
  • 理解隐式转换:自动类型转换
  • 掌握注解:元编程基础

1.2 为什么本章如此重要

隐式是 Scala 最独特也最强大的特性。它支撑了类型类、DSL、上下文抽象等高级模式。

1.3 核心问题引导

隐式参数如何工作?

类型类(Type Class)模式是什么?

注解有什么用途?


二、核心概念详解

7.1 隐式参数

scala
// 隐式参数: 自动传递
case class Config(timeout: Int, retries: Int)

def connect(url: String)(implicit config: Config): Unit = {
    println(s"Connecting to $url with timeout ${config.timeout}")
}

implicit val defaultConfig = Config(5000, 3)
connect("http://example.com")  // 自动传入 defaultConfig

// 类型类模式
trait Show[A] {
    def show(value: A): String
}

implicit val intShow: Show[Int] = (value: Int) => s"Int($value)"
implicit val stringShow: Show[String] = (value: String) => s"String($value)"

def display[A](value: A)(implicit s: Show[A]): String = s.show(value)

println(display(42))       // Int(42)
println(display("hello"))  // String(hello)

7.2 隐式转换

scala
// 隐式转换: 自动类型转换
class Fraction(val n: Int, val d: Int) {
    override def toString = s"$n/$d"
    def *(other: Fraction) = new Fraction(n * other.n, d * other.d)
}

object Fraction {
    implicit def intToFraction(n: Int): Fraction = new Fraction(n, 1)
}

import Fraction._

val result = 3 * new Fraction(1, 2)  // 3 自动转为 Fraction(3, 1)
println(result)  // 3/2

// 隐式类: 扩展方法
implicit class StringOps(val s: String) extends AnyVal {
    def shout: String = s.toUpperCase + "!"
    def whisper: String = s.toLowerCase + "..."
}

println("hello".shout)   // HELLO!
println("HELLO".whisper) // hello...

7.3 注解

scala
import scala.annotation._

// 内置注解
@deprecated("Use newMethod instead", "1.0")
def oldMethod(): Unit = {}

@tailrec
def factorial(n: Int, acc: Int = 1): Int = {
    if (n <= 1) acc
    else factorial(n - 1, n * acc)
}

@volatile var running = true

// 自定义注解
import scala.annotation.StaticAnnotation

class description(text: String) extends StaticAnnotation

@description("This is a person class")
case class Person(name: String, age: Int)

// 编译时注解处理需要宏 (macro)

三、实战案例

3.1 案例一:类型类实现 JSON 序列化

scala
// JSON 类型类
trait JsonWriter[A] {
    def write(value: A): String
}

object JsonWriter {
    def apply[A](implicit writer: JsonWriter[A]): JsonWriter[A] = writer
    
    // 内置实例
    implicit val stringWriter: JsonWriter[String] = 
        (value: String) => s""""$value""""
    
    implicit val intWriter: JsonWriter[Int] = 
        (value: Int) => value.toString
    
    implicit val boolWriter: JsonWriter[Boolean] = 
        (value: Boolean) => value.toString
    
    implicit def listWriter[A](implicit w: JsonWriter[A]): JsonWriter[List[A]] =
        (value: List[A]) => value.map(w.write).mkString("[", ",", "]")
    
    implicit def mapWriter[A](implicit w: JsonWriter[A]): JsonWriter[Map[String, A]] =
        (value: Map[String, A]) => 
            value.map { case (k, v) => s""""$k":${w.write(v)}""" }
                 .mkString("{", ",", "}")
}

// 语法糖
implicit class JsonOps[A](val value: A) extends AnyVal {
    def toJson(implicit writer: JsonWriter[A]): String = writer.write(value)
}

// 使用
println(42.toJson)                          // 42
println("hello".toJson)                     // "hello"
println(List(1, 2, 3).toJson)               // [1,2,3]
println(Map("a" -> 1, "b" -> 2).toJson)     // {"a":1,"b":2}

四、本章小结

隐式参数自动传递上下文,支持类型类模式

隐式转换和隐式类扩展已有类型

注解提供元数据


五、思考与练习

隐式解析的优先级规则是什么?

如何避免隐式转换的歧义?


7/7隐式与注
0%