implicit val x = 1
val y = implicitly[Int]
val z = implicitly[Double]
result:
scala> implicit val x = 1
x: Int = 1
scala> val y = implicitly[Int]
y: Int = 1
scala> val z = implicitly[Double]
<console>:11: error: could not find implicit value for parameter e: Double
val z = implicitly[Double]
context bound
implicitly
implicitly 主要是在当前作用域查找指定类型:
例子:
result:
为啥会报错呢,是因为当前作用域不能查找到Double的隐式值,如果要让他通过编译也很简单,定义一个Double的隐式值就可以了
那如果多个隐式值呢: 比如:
这就涉及到一个隐式解析规则问题了: scala的语言规范定义了以下两种查找标记为implicit的实体规则
而作用域和绑定主要是以下几条: 同作用域内的高优先级绑定遮挡低优先级的绑定,另外,高优先级或者同优先级的遮挡外部作用域的绑定 如:
以上内容基本来自scala in depth一书
所以这里就解释了关于隐式查找隐式实体的问题
context bound
首先先介绍两个概念,一个是
monoid
,这个表示有着满足结合律的封闭二元运算和一个单位元,这是一种代数数据结构 另一个是context bound以及简写:可以重写为
那么接下来让我们定义出IntMonoid来表示整数,以及求和运算,并且进行求和:
因为我们还可能进行String的运算,所以我们抽象了Monoid:
再次抽象sum
这样每次都写一个Monoid显得过于累赘:
我们再定义一个隐式参数:
这样就可以,还记得我们刚才说的上下文绑定么,sum是不是可以改写成上下文绑定的形式呢,当然可以:
最后我们组织下代码,我们可以将这种代数作为隐式值结构定义在伴生对象中,还记得我们说过的,当当前隐式实体的发生地点没找到,就会调用第二个规则,也就是在隐式参数的类型的隐式作用域所包含的全部隐式实体中查找,那么此时该类型的隐式作用域是指与该类型相关的全部伴生模块,所以可以去伴生对象中找:
此时都是可以运行的,那么下面看点黑魔法:
为啥product后面还能加参数,这是怎么了,还记得我们说的sum是什么的简写么,是带隐式参数的那种写法的简写:
和下面这种写法类似:
再看一个context bound的例子
上述demo出自learn scalaz,我稍微做了一些改变和讲解,另一个出自stackoverflow