首页 > 代码库 > scala学习手记35 - 隐式类型转换

scala学习手记35 - 隐式类型转换

先来看一下下面的内容:

2 days “ago”5 days “from_now”

如上的内容具体应该是什么呢?不过怎么看也不像是代码。不过既然是在学代码,拿不是代码的东西出来做什么!

非要强说是代码的话,那么执行起来肯定是要报错的——因为scala的Int和RichInt,以及Integer中都没有days这样的方法:

技术分享

如果说不是代码的话,那么scala中的to或until本来看起来也不像代码:

2 to 62 until 7

现在剩下的就是怎么为整型值添加上days方法。这就涉及到如何扩展整型类了。我自己想了好久也没想到妥帖的法子。

教材中提供了一个方案,就是采用隐式类型转换。

隐式类型转换可以帮助我们扩展语言,创建“专用于特定应用和领域”的词汇或语法,也可以帮助我们创建属于自己的领域专用语言。

关于隐式类型转换,教材上就是这么说的。从这句话里可以看到隐式类型转换为我们留下了巨大的扩展空间。

先来看看如何解决眼前的事情。要为整型值添加RichInt方法需要先创建一个DateHelper类:

class DateHelper(number: Int) {  def days(when: String): Date = {    val date = Calendar.getInstance()    when match {      case "ago" => date.add(Calendar.DAY_OF_MONTH, -number)      case "from_now" => date.add(Calendar.DAY_OF_MONTH, number)      case _ => date    }    date.getTime()  }}

在DateHelper类中提供了我们需要的days方法。我们要做的就是将给定的数字转换为DateHelper对象。类继承是不行的,强制类型转换也是不行的,可以考虑在需要的时候将整型值转换为DateHelper实例。简单的把方法标记为implicit,只要这个方法在当前范围内存在,scala就会自动调用这个方法:

implicit def convertInt2DateHelper(number: Int) = new DateHelper(number)

把上面的代码同DateHelper类一起运行就可以自动将整数值转换为DateHelper实例,然后就可以调用days()方法了。

来看一下完整的代码:

import java.util._class DateHelper(number: Int) {  def days(when: String): Date = {    val date = Calendar.getInstance()    when match {      case "ago" => date.add(Calendar.DAY_OF_MONTH, -number)      case "from_now" => date.add(Calendar.DAY_OF_MONTH, number)      case _ => date    }    date.getTime()  }}implicit def convertInt2DateHelper(number: Int) = new DateHelper(number)val ago = "ago"val from_now = "from_now"val past = 2 days agoval appointment = 5 days from_nowprintln(past)println(appointment)

看一下执行结果:

技术分享

接下来可以对代码稍作调整。我们并不想在每次需要转换时都去写隐式转换器。把这个转换器放到一个单独的单例对象里,可以获得更好的重用性,也更加易用。可以把转换器挪到DateHelper的伴生对象里:

import java.util._class DateHelper(number: Int) {  def days(when: String): Date = {    val date = Calendar.getInstance()    when match {      case DateHelper.ago => date.add(Calendar.DAY_OF_MONTH, -number)      case DateHelper.from_now => date.add(Calendar.DAY_OF_MONTH, number)      case _ => date    } date.getTime()  }}object DateHelper {  val ago = "ago"  val from_now = "from_now"  implicit def convertInt2DateHelper(number: Int) = new DateHelper(number)}

导入DateHelper时,Scala会自动的找到转换器。这是因为Scala会在当前范围和导入的范围内进行转换。

在Predef对象里,Scala已经定义了一些隐式转换,Scala会默认导入它们。这样的话,比如说,当我们写1 to 3时,Scala就会隐式的将1从Int转换为其富封装器RichInt,然后,调用to()方法。Scala一次至多应用一个隐式转换。

在当前范围内,如果发现通过类型转换有助于操作、方法调用或类型转换的成功完成,就会进行转换。

######################

scala学习手记35 - 隐式类型转换