当调用某个实例方法无相应方法实现。编译器开始寻找有隐式标记的函数字面量或方法,它可以将该实例转换成目标实例(可以调用目标方法的实例)
定义如下表达式
List(1, 2, 3) <= List(4, 5)
编译器
List 没有 <= 方法,无相关隐式转换,报错。
解决
经查询 Ordered[List[A]]
有该方法。故定义一个隐式转换方法,如下
import scala.language.implicitConversions
implicit def list2ordered[A](x: List[A])(implicit elem2ordered: A => Ordered[A]): Ordered[List[A]] =
new Ordered[List[A]] {
//replace with a more useful implementation
def compare(that: List[A]): Int = 1
}
编译器
List 没有 <= 方法,查询 List 类型相关的隐式转换。发现 list2ordered
符合要求,调用 list2ordered(List(1, 2, 3))
完成转换 Ordered[List[Int]]
,再调用它的 <= 方法。
补充说明
list2ordered
定义了一个隐式参数,参数类型是一个函数 Int => Ordered[Int]
。编译器在隐式转换时,调用 list2ordered
方法,缺少另一个隐式参数 elem2ordered
。
编译器开始自动寻找符合该参数类型的隐式标记。发现 implicit def intWrapper(x: Int) = new runtime.RichInt(x)
符合条件,因此传入 intWrapper
作为第二个参数。
-
规则
标记:implicit 可以标记变量、函数或对象
范围:finding-implicits
一次:只会试图转换一次
备选项 -
场景
隐式参数
隐式转换
Scala 在调用包含有隐式参数块的方法时,将首先查找可以直接访问的隐式定义和隐式参数 (无前缀)。 然后,它在所有伴生对象中查找与隐式候选类型相关的有隐式标记的成员。
示例
abstract class Monoid[A] {
def add(x: A, y: A): A
def unit: A
}
object ImplicitTest {
implicit val stringMonoid: Monoid[String] = new Monoid[String] {
def add(x: String, y: String): String = x concat y
def unit: String = ""
}
implicit val intMonoid: Monoid[Int] = new Monoid[Int] {
def add(x: Int, y: Int): Int = x + y
def unit: Int = 0
}
def sum[A](xs: List[A])(implicit m: Monoid[A]): A =
if (xs.isEmpty) m.unit
else m.add(xs.head, sum(xs.tail))
def main(args: Array[String]): Unit = {
// 我定义了接口,但不知道具体实现,并且我不想要直接显式声明这个参数。需要通过声明一个隐式参数方便注入具体的实现
println(sum(List(1, 2, 3))) // uses IntMonoid implicitly
println(sum(List("a", "b", "c"))) // uses StringMonoid implicitly
}
}
分析
调用 sum 函数时,发现少了一个参数 m。这个参数被标记为 implicit
,并且其类型为 Monoid[Int]
。接下来它开始在当前作用域寻找类型为 Monoid[Int]
的隐式定义或具有隐式标记的成员。发现隐式常量 intMonoid
满足条件,将其作为参数传入 sum 函数中。
隐式参数本质是一个参数,只不过它不需要主动传参,编译器会自动传递相应参数。它需要满足静态类型检查要求。即对传入的隐式变量可能会有一些限制,比如同一方法签名中相同的泛型变量必须保持一致。
语法糖
def f[A <% B](a: A) = a.bMethod
def f[A](a: A)(implicit ev: A => B) = a.bMethod
语法糖
def g[A : B](a: A) = h(a)
def g[A](a: A)(implicit ev: B[A]) = h(a)
举例:
def f[A](a: A, b: A)(implicit ord: Ordering[A]) = ord.compare(a, b)