Kotlin DSL

DSL 简述

相比于传统 API,DSL 更符合人类的语言习惯。
Domain Specific Language,专注于特定问题领域的计算机语言。

DSL 只是问题解决方案模型的外部封装,这个模型可能是一个 API 库、一个完整的框架等。

  1. HTML

对于 html 语言,kotlin 生态中 kotlinx.html 可在 web 应用中用于构建 html 的 DSL。
可以作为传统模版(JSP 等)等替代品。

kotlinx.html 分别提供了 kotlinx-html-jvmkotlinx-html-js 库的 DSL,用于在 JVM 和浏览器中直接使用 kotlin 代码来创建 html,释放了原有的 html 标签式的前端代码。

开发者可以使用 kotlin 编写传统意义的 html 页面了。

  1. Android

Kotlin 的 DSL 框架 Anko 是用于替代 Android 开发中布局 XML 文件的。

XML 本质上也是一种 DSL。
相比于 XML 风格的 DSL,Kotlin 原生的 DSL(Anko)风格更简单、灵活。

  • 内部 DSL,是基于通用编程语言实现的。
    Anko(Kotlin),Gradle(Java)。
  • 外部 DSL,从零开始构建的语言,需要实现语法分析器等,构建的难度相对较大。
    外部 DSL 更加专注特定领域。

Kotlin 的 DSL 特性支持

Kotlin 中创建 DSL 主要用到了 3 个特性:

  1. 扩展函数、扩展属性
  2. 高阶函数(带接收者的 Lambda 表达式)
  3. invoke 函数调用约定 (invoke 操作符函数)

invoke 操作符函数

class Hello {
    
    
    operator fun invoke(x: String): Unit {
    
    
        println("Hello, $x !")
    }
}

fun testInvoke(): Unit {
    
    
    val hello = Hello()
    // Hello实例的 invoke 方法调用(约定写法)
    // 这个特性在一般程序代码中很少用到,而它使得DSL代码更加简洁
    hello("Kotlin")
    // 输出:Hello, Kotlin !
}

流式 Kotlin DSL

集合类的 流式 Kotlin DSL

/**
 * 定义扩展函数
 */
fun <T: Comparable<T>> List<T>.sort() {
    
    
    // this 代表调用该函数的对象,也就是函数接收者
    Collections.sort(this)
}

// 测试 DSL
fun testListSort(): Unit {
    
    
    val list = listOf(1,5,2,9,6)
    list.sort()	// 调用
    println(list) // 输出:[1, 2, 5, 6, 9]
}
/**
 * 定义扩展函数
 */
fun <T: Comparable<T>> List<T>.reverse() {
    
    
    Collections.reverse(this)
}

// 测试 DSL
fun testListReverse(): Unit {
    
    
    val list = listOf(1,5,2,9,6)
    list.reverse()	// 调用
    println(list) // 输出:[6, 9, 2, 5, 1]
}
/**
 * 定义扩展函数
 */
fun <T: Comparable<T>> List<T>.binarySearch(x: T): Int {
    
    
    return Collections.binarySearch(this, x)
}

// 测试 DSL
fun testListBinarySearch(): Unit {
    
    
    val list = listOf(1,5,2,9,6)
    var index = list.binarySearch(1)	// 调用
    println(index) // 输出:0
    index = list.binarySearch(2)	// 调用
    println(index) // 输出:2
}

文件读写的 流式 Kotlin DSL

需求:创建一个函数,输入文件名,输出文件中每行文本的集合。

// 文件读写 流式 API
fun readFileLines(fileName: String): List<String> {
    
    
    return fileName.stream().buffered().reader("UTF-8").readLines()
}

// 测试
fun testReadFileLines(): Unit {
    
    
    val fileName = "./EasyKt.iml"
    println("==== $fileName : ====")
    val lines = readFileLines(fileName)
    lines.forEach(::println)
}
/**
 * 1. 给 String 扩展一个 stream()函数
 */
fun String.stream(): FileInputStream {
    
    
    return FileInputStream(this)
}

/**
 * 2. 给 FileInputStream 扩展一个 buffered() 函数
 */
fun FileInputStream.buffered(): BufferedInputStream {
    
    
    return BufferedInputStream(this)
}

/**
 * 3. 给 BufferedInputStream 扩展一个 reader() 函数
 */
fun BufferedInputStream.reader(charset: String): InputStreamReader {
    
    
    return InputStreamReader(this, charset)
}

/**
 * 4. 给 Reader 扩展一个 readLines() 函数
 */
fun Reader.readLines(): List<String> {
    
    
    val lines = arrayListOf<String>()
    forEachLine {
    
    
        lines.add(it)
    }
    return lines
}

集合类的 SQL风格 Kotlin DSL

fun testDSL_Sql(): Unit {
    
    
    val students = listOf(Student("Jane","W",18,80),
        Student("Jack","M",19,75),
        Student("Lucy","W",18,85),
        Student("Tyler","M",19,89),
    )
    // SQL 风格的过滤查询函数
    val query = students.select().where {
    
     it.score>79 }.and {
    
     it.sex == "W"}
    println(query)
    // 输出:[Student(name=Jane, sex=W, age=18, score=80), Student(name=Lucy, sex=W, age=18, score=85)]
}
data class Student(var name:String, var sex: String, var age:Int, var score: Int)
/**
 * 1. 给List 创建扩展函数 select()
 */
fun <E> List<E>.select(): List<E> = this

/**
 * 2. 给List 创建高阶函数 where();
 * where()函数的实现逻辑和 filter() 函数基本一致.
 */
fun <E> List<E>.where(predicate: (E) -> Boolean): List<E> {
    
    
    val list = this;
    val result = arrayListOf<E>()
    for (e in list) {
    
    
        if (predicate(e)) {
    
    
            result.add(e)
        }
    }
    return result
}

/**
 * 3. 给List 创建高阶函数 and();
 * and()函数的实现逻辑和 where() 函数一致,直接调用 where(predicate).
 */
fun <E> List<E>.and(predicate: (E) -> Boolean): List<E> {
    
    
    return where(predicate)
}

猜你喜欢

转载自blog.csdn.net/flyingyajun/article/details/122259863
DSL