# 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