Scala 隐式转换之一窥
学习 Spark 的键值对 RDD 时,对其的实现比较感兴趣——它是如何让特定类型的 RDD 拥有自己独有的方法的?于是就对此进行了一些了解,发现它的本质是比较浅显但又确实非常有趣的,现在做下笔记。
当调用对象的不存在的方法,以及调用方法时传递错误类型的对象时,Scala 都会试图在隐式视图中进行一番操作来“圆场”。
如果 Scala 发现用户试图调用对象的不存在的方法,则它会试图在隐式视图中寻找构造参数为当前对象类型的隐式类,并进行隐式转换,比如我们可以通过这种方式实现类的扩展——
1 |
|
如果 Scala 发现用户给一个类型为 B 的参数传递一个类型 A 的实例,则它会试图从隐式视图中选择一个A => B
的用于类型转换的函数。
1 |
|
最初的 Scala 没有隐式类,因此当时若要实现隐式类就只能通过隐式类型转换函数来实现,比如下面是不使用隐式类扩展 String 的方法——
1 |
|
容易想象,这种给类添加新操作的方法翻译到 Java 中,将得到所谓的“委托”模式,但 Scala 强大之处在于,用户完全可以对包装后的类一无所知,只需要在上下文中引入该隐式对象即可,这在 Java 中是不可能的。
但是 Scala 还能做的更多!考虑一个泛型类,假如我们有这样的需求,即希望这个泛型满足特定类型的时候,让它能够调用特定的方法,这倘若放到 Java 里,就只能通过反射进行检查了,而 Scala 做得到——
1 |
|
精巧绝伦!reduceByKey 等键值对 RDD 所特有的方法就是通过这种方式实现的。使用这种方式,既能把相关操作分离到不同地方以减少特定文件的大小,也能够避免用户对新的实现可知,统一实现的接口为 RDD;缺点则在于会让代码变得更加难懂,因此对其的使用应当是谨慎的,应在一定的模式下进行使用,期待之后的进一步学习。
也可以发现,这种操作和Haskell中的type class概念是很相近的——我们可以让类型成为一个typeclass的实例,从而让它们来具备更多方法,这种约束并非是利用接口,而是利用隐式转换,因此是可插拔的,且其能进行更多约束。这也是为什么Scala能通过像scalaz和cats等第三方库来给原有类型添加Monad等的操作。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 协议 ,转载请注明出处!