一个方法可以拥有隐式参数列表,它由_implicit_关键字在参数列表的开头作为标记。如果这个参数列表的参数没有正常传递的话,Scala会去查找一个正确类型的隐式值,如果找到了,则会自动传递。
Scala查找找些参数的位置分以下2种类型:
- 在带有隐式参数块的方法被调用时,Scala首先会查找可以直接访问(不需要加前缀)的隐式定义和隐式参数。
- 然后会查找与隐式候选类型相关联的所有伴生对象中标记为implicit的成员。
关于Scala查找隐式值的位置,在the FAQ有更加详细的讲解。
下面的例子中我们定义了一个方法sum,通过使用Monid的add和unit的操作来计算列表中元素的和。注意下面的隐式值不能在顶层。
1 | abstract class Monoid[A] { |
这里Monid类定义了一个方法add,用来组合一对A类型的值并且返回一个A类型的值,另外定义了一个unit方法用来创建一个具体的A类型的值。
为了展示隐式参数是如何起作用的,我们首先定义了针对字符串和整数的Monoid,分别是StringMonoid和IntMoniod。关键字implicit表明了相关的对象可以被隐式使用。
方法sum接受一个List[A]并且返回一个A,它从unit方法中获取一个A类型的初始值,然后使用add方法,对于列表中的每一个A类型的值进行组合。这里我们让参数m成为隐式的,意味着在调用方法的时候仅需要提供xs参数,其中前提是Scala可以查找到一个隐式的Monoid[A]来用于隐式的m参数。
在main方法中我们调用了sum两次,但是仅仅提供了xs参数。Scala会在上文提到的范围中寻找一个隐式值。第一次调用sum方法传递了一个List[Int]给xs,意味着A是Int。隐式参数列表m被忽略了,所以Scala会去查找一个Monoid[Int]类型的隐式值。首先应用第一条查找规则
在带有隐式参数块的方法被调用时,Scala首先会查找可以直接访问(不需要加前缀)的隐式定义和隐式参数。
intMonoid是一个隐式的定义,且可以在main方法中直接访问,并且是正确的类型,所以会自动地传递给sum方法。
第二次调用sum时传递了一个List[String],意味着A是String。此时隐式查找的方式会和Int一样,但这次查找到的是stringMonoid,并且自动传递给参数m。
该程序输出如下
1 | 6 |