scala的implicit def是一个非常重要而且容易被人忽视的特性,通过它能够模拟很多haskell/sml类型系统特有的能力。
考虑如下的接口
注意由于haskell是纯函数式语言,没有副作用,所以所有的类型都是covariant的。而scala做不到这一点,covarint、contravariant和invariant都会存在,所以这里的泛型参数没有协变。
我们想写一段“万能”的代码处理所有类型的filter操作,于是
现在问题来了,不是所有的对象都从Filter接口派生,我们有一个已存在的类,又不想改动既有的代码,怎么办呢?
答案就是implicit type。首先重写Filtering的实现,注意currying的第二个参数定义前加上了implicit
对于已存在的类 ExistsClass,我们创建一个新的定义,返回从Filter接口派生的基于ExistsClass的实现
这样问题就很简单了,由于implicit参数可以省略,编译器会自动地在编译的时候匹配,所以可以直接调用下面的代码。这样对于写好的抽象代码只需要增加implicit type,就可以无限地扩展到任何已存在的代码中,是不是很cool的性能?现在终于可以肆意地扩展已有的java library了
最后再介绍一下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的方法了!
通过上面两个例子我们看到implicit type巨大的潜力,scala的类型系统被称为"Poor Man's Type System",存在于已有的巨大的java资源上面,提供了高效、易于扩展和理解的功能。对scala的抽象类型、泛型的更多心得以后再记录。