转 http://blog.youkuaiyun.com/nethibernate/article/details/5893184
在学习Scala的时候,隐式转换(implicit conversion)这个特性让我实在是闹不住啊。于是乎一边试用一边感慨:真的是太强大,太方便了。
class LineNumber ( val num : Int ) |
val lineNumOfPage1 = new LineNumber(112) val lineNumOfPage2 = new LineNumber(120) |
上面的代码分别表示了第一页和第二页的行数。当然,我们也应该可以将它们相加,得到这两页的总行数:
val totalLineNum = lineNumOfPage1 + lineNumOfPage2 |
class LineNumber ( val num : Int ) { def + ( that : LineNumber ) = new LineNumber( this.num + that.num ) } |
从直观上讲,我们甚至可以直接用整数来和LineNumber相加:
val totalLineNumber = lineNumOfPage1 + 120 //或者 val totalLineNumber = 112 + lineNumOfPage2 |
object LineNumber{ implicit def intToLineNumber( i : Int ) = new LineNumber(i) implicit def lineNumberToInt( o : LineNumber ) = o.num } |
接下来再让我们尝试用LineNumber和整型相加:
import LineNumber._ val totalLineNumber1 = lineNumOfPage1 + 120 val totalLineNumber2 = 112 + lineNumOfPage2 |
我们会得到什么结果呢?
先让我们看看在编译时加入 “-Xprint:typer” 后上面两句的结果:
val totalLineNumber1: LineNumber = lineNumOfPage1.+(LineNumber.intToLineNumber(120));
val totalLineNumber2: Int = 112.+(LineNumber.lineNumberToInt(lineNumOfPage2));
|
到这里已经很清楚了。Scala编译器优先选择了方法的参数作为转换对象,而没有选择调用方法的对象。这是为什么呢?
- 第一个位置是 “可以直接将某个类型转换为期望的类型” 的地方
- 第二个位置是 “可以将调用方法的对象转换为合适类型” 的地方
第一个位置是那种我们需要A但是传入的却是B的地方。上面的例子正好就是这样的情况,对于totalLineNumber1来说,lineNumOfPage1的 “+” 方法需要的参数类型是LineNumber型,然而我们传入的是Int类型,Scala编译器在这里检测到类型错误后,会寻找将Int转换为LineNumber的隐式转换。因为在代码开始时,我们利用 "import LineNumber._ " 导入了相应的隐式转换,因此Scala编译器使用导入的隐式转换将整型120转换为了LineNumber类型。totalLineNumber2发生的情况是相同的,只不过是将LineNumber类型转换为了Int类型。
就像我开头所说的那样,Scala的隐式转换是一个非常强大的工具,但是如果不了解它,或者将其滥用在程序中,会使得程序难以理解和维护。真的到了那个时候,就确实“闹不住”了。