最近看了下 Scala程序設計,覺得里面的隱式類型轉換蠻有趣的,可以寫出DSL的效果。這篇小文就是想分享下如何寫出類似" 2 days ago"和“2 days from_now"這樣的代碼。為了好玩點,我也會寫一個" I Love You"這樣的DSL,並且然后程序可以正常編譯。首先看看如何寫成”2 days ago" 這樣的效果。請看如下代碼:
package helper { import java.util.Calendar import java.util.Date class DateHelper private(number: Int) { def days(when: String): Date = { var 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 convertInt2Date(number: Int) = new DateHelper(number) } }
簡單分析下上面的代碼。
首先,我們定義了一個名為helper的package,然后package里面定義一個private類型的DateHelper類以及其伴生對象。在伴生對象中,我們注意到有一個convertInt2Date方法,並且用"implicit"做了修飾。用"implicit"修改的方法很特殊,它會在類被導入時自動執行,並且將其參數進行隱式轉換,如代碼中將Int類型轉換為了DateHelper類型。 這樣當我們調用Int類型的方法時 會自動變為DateHelper類型。看看如何使用這個DateHelper就明白了。
import helper.DateHelper._ object Sample { def main(args: Array[String]): Unit = { val twoDayAgo = 2 days ago val twoDayAfter = 2 days from_now println("two days ago is " + twoDayAgo) println("two days after is " + twoDayAfter) } }
返回結果:
two days ago is Fri May 31 22:16:58 CST 2013 two days after is Tue Jun 04 22:16:58 CST 2013
事實上,"2 days ago" 相當於調用 2.days(ago), 因為Scala的方法中的點號可以省略,括號也可以省略,所以看起來就像DSL了。
也許有朋友會問,那這個"ago"怎么來的?好問題!我們看DateHelper的伴生對象,里面不是有定義了一個ago變量么,變量的值就是"ago", 然后導入DateHelper._時,將其也導入進來了,所以可以直接訪問。其實就是 2.days("ago"), 換湯不換葯而已。
調用DateHelper中的days方法時,我們用到了模式匹配,只有當傳入的參數值為DateHelper.ago和DateHelper.from_now時,我們才進行處理,其他情況一律返回當前日期。
很簡單吧,但是真的很強大!現在,我們在看一個" I Love You"的效果。當代碼中寫入"I Love You" 時,程序打印出"I love You"
package love { class LoveHelper private(who: String) { def love(beLoved: String) = { beLoved match { case LoveHelper.You => println(who + " Love " + beLoved) case _ => println("You don't love " + beLoved ) } } } object LoveHelper { val I = "I" val You = "You" implicit def conver(who: String) = new LoveHelper(who) } }
程序調用:
import love.LoveHelper._ object LoveSample { def main(args: Array[String]): Unit = { I love You I love "marry" } }
運行結果為:
I Love You You don't love marry
如果明白了DateHelper的例子,這個就非常簡單了。這個代碼是地String類型做了隱式轉換,轉換為LoveHelper對象,然后調用里面的love方法。
Scala真的非常強大,可以寫成簡單易讀的DSL代碼出來,為我們的coding life增加了不少色彩,大家也可以玩一玩哦!