Scala之旅-隐式参数

Scala之旅-隐式参数

隐式参数(Implicit Parameters)

带有隐式参数的方法可以像正常的方法那样使用参数。在这种情况下implicit标注是没有影响的。然而,如果这种方法的隐式参数没有被传递参数值,其参数值是会被自动提供的。

可以被传递给隐式参数的参数值需要符合如下两个策略:

  • 首先,参数值是在方法调用点不需要带前缀就可以访问的标识符,这表示一个隐式定义或者一个隐式参数。
  • 其次,参数值是用implicit标注的隐式参数的类型的伙伴模块(companion modules)的所有成员。

下面的例子中,我们定义了一个方法sum,它使用monoid的操作add和unit计算一个列表所有元素之和。请注意隐式值不能在最外层,它们必须是一个模版的成员。

/** This example uses a structure from abstract algebra to show how implicit parameters work. A semigroup is an algebraic structure on a set A with an (associative) operation, called add here, that combines a pair of A's and returns another A. */
abstract class SemiGroup[A] {
  def add(x: A, y: A): A
}
/** A monoid is a semigroup with a distinguished element of A, called unit, that when combined with any other element of A returns that other element again. */
abstract class Monoid[A] extends SemiGroup[A] {
  def unit: A
}
object ImplicitTest extends App {
  /** To show how implicit parameters work, we first define monoids for strings and integers. The implicit keyword indicates that the corresponding object can be used implicitly, within this scope, as a parameter of a function marked implicit. */
  implicit object StringMonoid extends Monoid[String] {
    def add(x: String, y: String): String = x concat y
    def unit: String = ""
  }
  implicit object IntMonoid extends Monoid[Int] {
    def add(x: Int, y: Int): Int = x + y
    def unit: Int = 0
  }
  /** This method takes a List[A] returns an A which represent the combined value of applying the monoid operation successively across the whole list. Making the parameter m implicit here means we only have to provide the xs parameter at the call site, since if we have a List[A] we know what type A actually is and therefore what type Monoid[A] is needed. We can then implicitly find whichever val or object in the current scope also has that type and use that without needing to specify it explicitly. */
  def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
    if (xs.isEmpty) m.unit
    else m.add(xs.head, sum(xs.tail))

  /** Here we call sum twice, with only one parameter each time. Since the second parameter of sum, m, is implicit its value is looked up in the current scope, based on the type of monoid required in each case, meaning both expressions can be fully evaluated. */
  println(sum(List(1, 2, 3)))          // uses IntMonoid implicitly
  println(sum(List("a", "b", "c")))    // uses StringMonoid implicitly
}

该程序的输出如下:

6
abc

参考资料

本文译自Tour Of Scala – Implicit Parameters

上一篇:Scala之旅-自身类型

下一篇:Scala之旅-隐式转换

发表评论

电子邮件地址不会被公开。 必填项已用*标注