一个方法可以拥有隐式参数列表,它由_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 |