Scala 之旅

上下文参数,又称隐式参数

语言

方法可以具有上下文参数,也称为隐式参数,或更简洁地称为隐式。以关键字 using(或 Scala 2 中的 implicit)开头的参数列表标记上下文参数。除非调用站点明确为这些参数提供参数,否则 Scala 将查找正确类型的隐式可用 given(或 Scala 2 中的 implicit)值。如果可以找到合适的值,它会自动传递它们。

首先,使用一个小示例最能说明这一点。我们定义一个接口 Comparator[A],它可以比较类型 A 的元素,并提供两个实现,用于 IntString。然后,我们定义一个方法 max[A](x: A, y: A),它返回两个参数中较大的那个。由于 xy 是泛型类型,因此通常我们不知道如何比较它们,但我们可以要求提供一个合适的比较器。由于对于任何给定的类型 A 通常都有一个规范比较器,因此我们可以将它们声明为给定值隐式可用。

trait Comparator[A] {
  def compare(x: A, y: A): Int
}

object Comparator {
  implicit object IntComparator extends Comparator[Int] {
    def compare(x: Int, y: Int): Int = Integer.compare(x, y)
  }

  implicit object StringComparator extends Comparator[String] {
    def compare(x: String, y: String): Int = x.compareTo(y)
  }
}

def max[A](x: A, y: A)(implicit comparator: Comparator[A]): A =
  if (comparator.compare(x, y) >= 0) x
  else y

println(max(10, 6))             // 10
println(max("hello", "world"))  // world
// does not compile:
println(max(false, true))
//         ^
//     error: could not find implicit value for parameter comparator: Comparator[Boolean]

对于 max(10, 6)comparator 参数会自动填充为 Comparator.IntComparator,对于 max("hello", "world"),会自动填充为 Comparator.StringComparator。由于找不到隐式的 Comparator[Boolean],因此调用 max(false, true) 时无法编译。

trait Comparator[A]:
  def compare(x: A, y: A): Int

object Comparator:
  given Comparator[Int] with
    def compare(x: Int, y: Int): Int = Integer.compare(x, y)

  given Comparator[String] with
    def compare(x: String, y: String): Int = x.compareTo(y)
end Comparator

def max[A](x: A, y: A)(using comparator: Comparator[A]): A =
  if comparator.compare(x, y) >= 0 then x
  else y

println(max(10, 6))             // 10
println(max("hello", "world"))  // world
// does not compile:
println(max(false, true))
-- Error: ----------------------------------------------------------------------
1 |println(max(false, true))
  |                        ^
  |no given instance of type Comparator[Boolean] was found for parameter comparator of method max

对于 max(10, 6)comparator 参数会自动填充为 given Comparator[Int],对于 max("hello", "world"),会自动填充为 given Comparator[String]。由于找不到 given Comparator[Boolean],因此调用 max(false, true) 时无法编译。

Scala 会在两个地方查找可用的给定值

  • Scala 首先会在 max 的调用位置查找给定定义,并使用可以直接访问(没有前缀)的参数。
  • 然后它在与隐式候选类型关联的伴生对象中查找标记为 given/implicit 的成员(例如:对于候选类型 Comparator[Int]object Comparator)。

可以在 常见问题解答 中找到 Scala 在何处查找隐式内容的更详细指南。

此页面的贡献者