方法可以具有上下文参数,也称为隐式参数,或更简洁地称为隐式。以关键字 using
(或 Scala 2 中的 implicit
)开头的参数列表标记上下文参数。除非调用站点明确为这些参数提供参数,否则 Scala 将查找正确类型的隐式可用 given
(或 Scala 2 中的 implicit
)值。如果可以找到合适的值,它会自动传递它们。
首先,使用一个小示例最能说明这一点。我们定义一个接口 Comparator[A]
,它可以比较类型 A
的元素,并提供两个实现,用于 Int
和 String
。然后,我们定义一个方法 max[A](x: A, y: A)
,它返回两个参数中较大的那个。由于 x
和 y
是泛型类型,因此通常我们不知道如何比较它们,但我们可以要求提供一个合适的比较器。由于对于任何给定的类型 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 在何处查找隐式内容的更详细指南。