在 Scala 2.10.0 之前类型的隐式转换必须通过隐式方法来完成,现在的 Scala 可以用 implicit class 来声明类,并且它的主构造器 (Primary Constructor) 只有一个参数时,就可以用来把参数隐式转换成该类型。
能理解上面什么意思,知道怎么用隐式类吗? 就上面那句话,我自己都不知道在说什么。
首先要知道 Scala 先前是怎么依据隐式方法进行类型的隐式转换,其次又何谓主构造器呢? 关于 Scala 2.10.0 的 implicit class,官方的解释在这里 http://docs.scala-lang.org/sips/pending/implicit-classes.html 再多说只能让大家更摸不到头,实例演示是王道:
效果应该很明显。字符串在调用 sayHello 方法时,发现自己没有这个方法,就试图用某种方式转型成具有 sayHello 方法的类型,这里它找到了 implicit class 这个隐式类可以用来转型成 Person 类,最后调用了生成的 Person 实例的 sayHello 方法。
那什么是主构造函数呢,就是跟在 class 关键字后面那部分,因为 Scala 比 Java 更省事,声明类的时候把主构造函数也一同声明了。
implicit class 类名后的参数列表必定是一个参数的,否则会报错: error: implicit classes must accept exactly one primary constructor parameter 因为这种类型的类非常大的一个用途就是用作隐式转型。
回想一下,之前需要通过隐式方法来进行隐式转型,类似的,这样的隐式方法也必须是只能一个参数。实质上隐式类就是声明类的同时,还帮你创建了一个隐式方法用来转型用,并且这个原本就叫做隐式方法的方法比原来隐藏的更深了,这样就好理解了吧。
既然我们已经有了隐式方法帮助转型为何还要增加一个隐式类的概念呢? 我的观点有如下几个(敝人列举的时候一般以几点开头,因为不是领导,而且再点点的同时还正在思考,许多东西都是在思考的时候发掘出来的):
1. implicit class 的时候把类型和隐式方法都准备好了,无须像下面这样分两步:
1 2 3 4 5 |
class Person(val name: String) { def sayHello = s"Hello I'm $name." } implicit final def str2Person(name: String) = new Person(name) |
先声明一个类,再声明隐式方法来创建这个类实例。而且这个隐式方法与类是分离的。
2. 用声明的隐式方法转型,这个隐式方法必须是对当前作用域可见,或是存在于目标类型的伴生对象中。如果是存在别的类中,如 cc.unmi.MyClass 中,必须用 import cc.unmi.MyClass._ 像静态引入一样包括进来,光 import cc.unmi.MyClass 到这个级别还不够。如果是用的隐式类,引入这个隐式类即可。
还能补充吗? 我们说隐式类由主构造函数自动具有一个隐式方法,虽然这样的类看起来很干净,但因此也只能有这么一个转型方法,想要更多的转型方法,还是要呼唤隐式方法。当然隐式方法方法真多了,你一定会迷惑的。
另外,对隐式类标注的 Annotation @bar,实际会同时标注到类和隐式方法上去了,但这个 Annotation 写成 @(bar genClass) 的话只会作用了类上。
参考:http://docs.scala-lang.org/sips/pending/implicit-classes.html
本文链接 https://yanbin.blog/scala-2-10-new-features-implicit-class/, 来自 隔叶黄莺 Yanbin Blog
[版权声明] 本文采用 署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0) 进行许可。