scala学习笔记(5) -- implicit type

scala的implicit def是一个非常重要而且容易被人忽视的特性,通过它能够模拟很多haskell/sml类型系统特有的能力。

考虑如下的接口

scala 代码
  1. trait Filter[a] {   
  2.   def filter(input:a)(f: a=>Boolean):Option[a]   
  3. }  

注意由于haskell是纯函数式语言,没有副作用,所以所有的类型都是covariant的。而scala做不到这一点,covarint、contravariant和invariant都会存在,所以这里的泛型参数没有协变。

我们想写一段“万能”的代码处理所有类型的filter操作,于是

scala 代码
  1. object Filtering{   
  2.   def filter[a](input: a)(f: a=> Boolean)(filter: Filter[a]): Option[a] =    
  3.     return filter.filter(input)(a)   
  4. }  

现在问题来了,不是所有的对象都从Filter接口派生,我们有一个已存在的类,又不想改动既有的代码,怎么办呢?

答案就是implicit type。首先重写Filtering的实现,注意currying的第二个参数定义前加上了implicit

scala 代码
  1. object Filtering{   
  2.   def filter[a](input: a)(f: a=> Boolean)(implicit filter: Filter[a]): Option[a] =    
  3.     return filter.filter(input)(f)   
  4. }  

 对于已存在的类 ExistsClass,我们创建一个新的定义,返回从Filter接口派生的基于ExistsClass的实现

scala 代码
  1. implicit def implicitExists = new Filter[ExistsClass] {   
  2.   def filter(input:ExistsClass)(f: ExistsClass=>Boolean):Option[ExistsClass] =    
  3.      if (f(input)) Some(input) else  None    
  4. }  

这样问题就很简单了,由于implicit参数可以省略,编译器会自动地在编译的时候匹配,所以可以直接调用下面的代码。这样对于写好的抽象代码只需要增加implicit type,就可以无限地扩展到任何已存在的代码中,是不是很cool的性能?现在终于可以肆意地扩展已有的java library了

scala 代码
  1. scala> Filtering.filter(new ExistsClass)(a => true)   
  2. unnamed20: Option[ExistsClass] = Some(ExistsClass@1dae827)   
  3.   
  4. scala> Filtering.filter(new ExistsClass)(a => false)   
  5. unnamed21: Option[ExistsClass] = None  

 

最后再介绍一下implicit的另一个重要应用:type view。熟悉design pattern的人都知道wrapper pattern,当需要使用第三方的库又无法直接继承的时候,通常需要手工写一些wrapper method,如果恰巧要扩展的库有很多方法,无疑是一个非常枯燥的工作。通过scala的implicit type,我们可以定义一个类型的某种特殊的view,当compiler遇到一个对类型的未定义操作的时候,会在当前的compiler scope中自动寻找匹配的implicit def,这样对第三方的库进行扩展变成很简单的操作,implicit def一个view函数就好了。这一切都是编译期决定的,不会对性能有太大的损失,而且也保证了类型的安全性。

下面的例子,immuteClass只有simple方法,通过定义wrapperClass和implicit转换函数implicitWrapper,我们为immuteClass增加了一个wrapperClass的view,这样new出来的immuteClass对象(注意是immuteClass对象!)就可以调用wrapperClass的方法了!

scala 代码
  1. final class immuteClass {   
  2.   def simple = println("simple function")   
  3. }   
  4. class wrapperClass(imclass: immuteClass) {   
  5.   def advance = println("advance function")   
  6. }   
  7. object MainClass{   
  8.   implicit def implicitWrapper(im: immuteClass) = new wrapperClass(im)   
  9.   def main(args:Array[String]) {   
  10.     val im = new immuteClass   
  11.     // call simple method in immuteClass    
  12.     im.simple   
  13.     // immuteClass doesn't have advance method, so implicitWrapper automaticlly invoked   
  14.     // 等价于 implicitWrapper(im).advance   
  15.     im.advance       
  16.   }   
  17. }  


通过上面两个例子我们看到implicit type巨大的潜力,scala的类型系统被称为"Poor Man's Type System",存在于已有的巨大的java资源上面,提供了高效、易于扩展和理解的功能。对scala的抽象类型、泛型的更多心得以后再记录。


你可能感兴趣的:(工作,scala,F#,haskell)