# 1. 前言
為了了解什么是`DSL`,這里我百度了一下:
> `DSL`(`domain specific language`),即**領域特定語言**,是編程的一種范式。專門解決某一特定問題的計算機語言,比如大家耳熟能詳的 `SQL` 和正則表達式。`DSL` 只專注于某個領域,比如 `SQL` 僅支持數據庫的相關處理,而正則表達式只用來檢索和替換文本,我們無法用 `SQL` 或者正則表達式來開發一個完整的應用。DSL 往往具備**獨特的代碼結構和一致的代碼風格**。
以上內容摘自:[Kotlin之美——DSL篇 - 簡書 (jianshu.com)](https://www.jianshu.com/p/f5f0d38e3e44)
# 2. 簡單使用DSL
## 2.1 變換
變換是函數式編程的第一大類函數,會遍歷集合內容,以值參形式傳入的變換器函數,變換每一個元素,然后返回修改后元素。通常使用的函數為`map`和`flatMap`。
### 2.1.1 map
~~~
fun main() {
var users = listOf("張三", "李四", "王五")
// 使用map進行變換
val maped = users.map { it -> "我是$it" }
println(users)
println(maped)
}
~~~
結果:
```
[張三, 李四, 王五]
[我是張三, 我是李四, 我是王五]
```
類似的,這里也可以為`flatMap`來做一個簡單的案例。
### 2.1.2 flatMap
這個函數可以將多個集合合并,返回一個集合。
~~~
fun main() {
var users = listOf(
listOf("張三", "張思"),
listOf("李四", "李六")
)
// 合并集合的集合
val flatMap = users.flatMap { it }
println(flatMap)
}
~~~
結果:
```
[張三, 張思, 李四, 李六]
```
## 2.2 過濾
過濾函數接收一個斷言函數,按照條件給出`true`或者`false`,如果按照條件判斷為`true`就留在集合,否則被移除。需要注意的是,這里的保留或者移除還是在副本中進行,不修改原本集合。
### 2.2.1 filter
~~~
fun main() {
var users = listOf("張三", "李四", "王五", "趙六")
val filteredUsers = users.filter { it.contains("王") }
println(users)
println(filteredUsers)
}
~~~
結果:
```
[張三, 李四, 王五, 趙六]
[王五]
```
再比如我們需要在一堆數據中找素數:
~~~
fun main() {
var datas = listOf(
listOf(1, 4, 5, 6, 7, 20),
listOf(3, 5, 7, 9, 0, 13)
)
// 找datas中的素數
val filter = datas.flatMap { it }.filter { data ->
(2 until data).map { data % it }
.none { it == 0 } // Returns `true` if no elements match the given [predicate].
}
println(filter)
}
~~~
結果:
```
[1, 5, 7, 3, 5, 7, 0, 13]
```
注意到`(2 until data)`返回的為`[2, ..., data-1]`。由于`filter`的斷言函數為`true`或者`false`,這里需要使用`none`來逐個元素判斷是否滿足斷言條件。觀看其源碼,可以將其寫為下面的函數:
~~~
// 等價寫法
fun judgement(data: Int): Boolean{
var list: MutableList<Int> = mutableListOf()
for (i in 2 until data){
list.add(data % i)
}
// none
for (element in list) {
// 如果能夠被2到data-1的任意一個數整除,表示不是素數
if (element == 0) return false
}
return true
}
val filter1 = datas.flatMap { it }.filter { data -> judgement(data) }
println(filter1)
~~~
結果:
```
[1, 5, 7, 3, 5, 7, 0, 13]
```
這里再摘抄一下`none`的源代碼:
~~~
/**
* Returns `true` if no elements match the given [predicate].
*
* @sample samples.collections.Collections.Aggregates.noneWithPredicate
*/
public inline fun <T> Iterable<T>.none(predicate: (T) -> Boolean): Boolean {
if (this is Collection && isEmpty()) return true
for (element in this) if (predicate(element)) return false
return true
}
~~~
當然,有些時候我們需要的是取`topk`個元素,所以這里可以使用`take`函數:
~~~
// 判斷一個數是否是素數 【擴展函數】
fun Int.isPrime(): Boolean {
(2 until this).map {
if(this % it == 0)
return false
}
return true
}
fun main() {
var datas = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
// 找datas中的素數,并取前3個
val take = datas.filter { data -> data.isPrime() }.take(3)
println(take)
}
~~~
結果:
```
[1, 2, 3]
```
## 2.3 映射合并
### 2.3.1 zip
也就是使用`zip`函數,進行`key-value`的兩個集合的合并。比如下面的案例:
~~~
fun main() {
var keys = listOf("zs", "ls", "ww")
var users = listOf("張三", "李四", "王五")
val zip = keys.zip(users)
println(zip)
}
~~~
結果:
```
[(zs, 張三), (ls, 李四), (ww, 王五)]
```
從上面結果中可以看出,結果為二元組的列表。有時候我們所期望的是一個`Map`集合,所以,我們可以進一步進行處理:
~~~
val zip = keys.zip(users).toMap()
~~~
結果:
~~~
{zs=張三, ls=李四, ww=王五}
~~~
不妨來看一下`zip`的源碼:
~~~
public infix fun <T, R> Iterable<T>.zip(other: Iterable<R>): List<Pair<T, R>> {
return zip(other) { t1, t2 -> t1 to t2 }
}
~~~
可以簡單解讀下,首先回顧一下`infix`關鍵字:
> 當定義的擴展函數只有一個參數,可以使用`infix`來進行簡化,如果定義函數的時候使用了這個關鍵字,那么點操作符以及參數的括號都可以不要。
- 使用`infix`關鍵字,可以支持在調用的時候不要點操作符以及參數的括號;
- 使用泛型`<T, R>`,方便支持各種類型;
- 傳入一個列表,返回一個列表對,類型為`<T, R>`,即:調用列表元素類型和傳入參數元素類型;
### 2.3.2 fold
接收一個初始累加器的值,然后根據傳入的函數進行值的更新,最后進行累加。
~~~
fun main() {
var datas = listOf(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
val fold = datas.fold(10) { accumulator, element ->
accumulator + element
}
println(fold)
}
~~~
結果:
```
65
```
其實看`fold`的源碼也可以知道其原理:
~~~
public inline fun <T, R> Iterable<T>.fold(initial: R, operation: (acc: R, T) -> R): R {
var accumulator = initial
for (element in this) accumulator = operation(accumulator, element)
return accumulator
}
~~~
其實也就是`for`循環來完成的操作。
- Kotlin語言基礎
- Kotlin的簡介
- Kotlin的變量和常見數據類型
- Kotlin的區間
- Kotlin的位運算
- Kotlin的容器
- Kotlin類型檢查
- Kotlin的空值處理
- Kotlin的函數
- Kotlin的類
- Kotlin的委托
- Kotlin的延遲加載
- Kotlin的異常
- Kotlin的Lambda表達式
- Kotlin的高階函數
- Kotlin的標準庫中的高階函數
- Kotlin的泛型
- Kotlin的表達式
- Kotlin的解構
- Kotlin的運算符重載
- Kotlin語言中級
- Kotlin的擴展函數
- Kotlin的擴展屬性
- Kotlin的infix關鍵字
- Kotlin的DSL
- Kotlin的一些注解(和Java互調用)
- Kotlin的lateinit和by lazy
- Kotlin的反射
- Kotlin的匿名接口
- 安卓中的Kotlin
- 數據庫操作Room