先来看一下下面的内容:
2 days “ago”
5 days “from_now”
如上的内容具体应该是什么呢?不过怎么看也不像是代码。不过既然是在学代码,拿不是代码的东西出来做什么!
非要强说是代码的话,那么执行起来肯定是要报错的——因为scala的Int和RichInt,以及Integer中都没有days这样的方法:
如果说不是代码的话,那么scala中的to或until本来看起来也不像代码:
2 to 6 2 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 ago val appointment = 5 days from_now println(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一次至多应用一个隐式转换。
在当前范围内,如果发现通过类型转换有助于操作、方法调用或类型转换的成功完成,就会进行转换。
######################