kotlin 基礎 21 DSL(領域特定語言)

kotlin.jpeg
什麼是 DSL(領域特定語言)呢?
先說一下他好處吧,就是讓更多人更容易地接觸到程式設計,讓程式語言更接近人類語言。許多語言在設計之初都在考慮是對人類更友好一些,還是對計算機更用好一些呢。DSL 無疑對人類更友好。可以讓更多人加入的 developer 大軍中來。
大家熟悉的 css 和 SQL 語言都是典型的 DSL 語言,我們在寫 SQL 語言可能感觸很深,感覺自己在寫英文語句而非程式語言。
大家可能注意到了 領域 ,所謂 領域 也就是限定語言是適用於一定範圍的。CSS 專注定義我們頁面結構和樣式,包括顏色和尺寸等等,而 SQL 專注於對資料的操作。
DSL 包括兩種型別,External 和 Internal
External 型別,你可以定義規則、定義語法、比較靈活,同時也帶來大量的工作,需要自己寫解析器。
Internal,語言本身提供 DSL 特性,無需自己寫 parser 造輪子。但是也需要對語言瞭解熟悉,然後通過現有資源和條件來實現我們 DSL
context 和 fluency
context 可以理解為共同語言,那麼什麼是夫妻間的共同語言呢,簡單我們可以談論都看過電影,我們不需要給出過於詳細資訊對方也能讀懂我們想法,理解彼此意圖。

Mr-and-Mrs-Smith.jpg
fluency 所謂流暢,就是 DSL 需要更接近人類語法,通過一系列 word 清楚表達一定意思。kotlin 雖然是一門靜態語言,但是從他語法和特性來看可以實現一定 fluent。
kotlin 語言本身特性
程式碼結尾分號可省略
還得說 java 我們必須寫 ; 結尾。
println("hello")
那麼回到主題,分號結尾對我們 DSL 有什麼影響呢,顯而易見影響我們語言的 fluent 流暢性。
我們可以省略 . 代替用空格。
class Car{ fun drive(dist: Int){ println("driving...") } } fun main() { val car = Car() car.drive(10) }
我們這裡呼叫 car 的 drive 方法是通過(.) car.drive(10)
,我們想寫出 car drive 10
這樣看起來更接近人類語言。
infix fun drive(dist: Int){ println("driving...") }
inflix 告訴編譯器多這段程式碼檢查可以放寬鬆些。
方法的擴充套件
為了提高 DSL 語言的可讀性,我們在定義方法名要下一些功夫,但是有些第三方庫提供方法名並不能滿足 DSL 對 fluent 要求。
fun main() { val car = Car() var greeting = "hello" fun String.shout() = toUpperCase() println(greeting.shout()) //car drive 10 }
toUpperCase
這個方法名顯然對 DSL 語言不那麼友好,我們需要給他換一個名詞來在 DSL 語言中使用。kotlin 又是如何實現的呢?kotlin 並不像其他語言對位元組碼進行注入,而是通過語法糖包裹來實現,編譯器,將 shout 函式接受 String 型別作為引數然後進行重寫
fun process(func:(n:Int) -> Unit, n:Int){ func(n * 2) }
fun List<Tut>.findCoursesGreaterThan(course:Int){ filter { it.courses > course }.forEach(::println) }
tuts.findCoursesGreaterThan(60)
Tut(title=rust base, courses=120, author=tina, category=native)
infix fun List<Tut>.findCoursesGreaterThan(course:Int){ filter { it.courses > course }.forEach(::println) }
tuts findCoursesGreaterThan 60