Kotlin - DSL
data class Person(var name: String? = null,var age: Int? = null,var address: Address? = null
)data class Address(var street: String? = null,var number: Int? = null,var city: String? = null
)fun person(block: Person.() -> Unit): Person = Person().apply(block)
//提供Address实例创建的扩展函数(定义为扩展函数避免污染Person类)
fun Person.address(block: Address.() -> Unit) {address = Address().apply(block)
}val person = person {name = "John"age = 25address {street = "Main Street"number = 42city = "London"}
}
一、使用到的Kotlin语言特性
扩展函数/属性 详见文章 |
为任意对象增加函数或属性,还能链式调用。(例如不用传参Context) |
中缀表达式 详见文章 |
让函数调用省略.(),实现类似于英语句子的结构增强可读性。 |
Lambda 详见文章 |
简写函数,传参使用。 |
高阶函数:函数形参可以传入Lambda,且最后一个参数是Lambd可以放在括号外面实现了大括号层级。(将对象创建及初始化逻辑封装成最后一个形参是lambda的高阶函数中) |
|
带接收者的Lambda:大括号中对it的饮用变为可以省略掉的this,让成员函数/属性调用更简洁。 |
|
invoke约定:把对象当作函数名一样调用函数,让函数变量像 对象调用函数 一样调用自身。 |
|
内联函数 详见文章 |
大量的高阶函数会产生大量的匿名类,使用 inline 减少生成提升性能。(内联函数内部调用的函数必须是public的,对于protected声明的函数使用@PublishedApi即可解决) |
变长参数 详见文章 |
纵向一行写一个要添加的参数。 |
1.1 扩展函数/属性
//扩展函数
fun Int.days() = Period.ofDays(this)
fun Period.ago() = LocalDate.now() - this
//使用效果
val aa = 123.days().ago()
//扩展属性
val Int.days: Periodget() = Period.ofDays(this)
val Period.ago: LocalDateget() = LocalDate.now() - this
//使用效果
val aa = 123.days.ago
1.2 中缀表达式
//举例一
object ago
infix fun Int.days(ago: ago) = LocalDate.now() - Period.ofDays(this)
//使用效果
val aa = 123 days ago
//举例二
object start
infix fun String.should(start: start): String = ""
infix fun String.with(str: String): String = ""
//使用效果
val aa = "kotlin" should start with "K"
1.3 Lambda特性
1.3.1 简写函数、传参使用
//简写函数
fun sum(x: Int, y: Int): Int {...}
val aa: (Int, Int) -> Int = { x, y -> ... }
//传参使用
fun show(block: (Int, Int) -> Int) {...}
show(aa)
1.3.2 高阶函数
fun layout(block: () -> Unit) {...}
fun button(str: String, block: () -> Unit) {...}
//使用
layout { button("click"){...}
}
1.3.3 带接收者的Lambda
fun show(block: StringBuilder.() -> Unit) {}
//使用
show {append("aaa")reverse()insert(1, "b")
}
1.3.4 invoke约定
class Dependencies{fun compile(coordinate:String){println("add $coordinate")}operator fun invoke(block:Dependencies.()->Unit){block()}
}
//使用效果
val dependencies = Dependencies()
//Gradle中用法
dependencies {compile("com.android.support:appcompat-v7:27.0.1")
}
//等价于
dependencies.compile("com.android.support:appcompat-v7:27.0.1")
二、构建器模式
实际开发中,类中属性会有val限制后期改变,因此只能调用构造函数来创建对象。
data class Person(val name: String,val birthday: Date,val address: Address?
)data class Address(val street: String,val number: Int,val city: String
)class PersonBuilder {//构建器中提供和Person相同的属性用来后期赋值(构建数据)var name = ""var birthday: String = "" //这里使用的是String,提供更可读的方式传参private var address: Address? = null //这里使用private修饰,后期就不能直接对该属性赋值,只能调用提供的address()函数创建对象来赋值//将传参的String类型转为Dateprivate var _birthday: Date = Date().apply {SimpleDateFormat("yyy-MM-dd").parse(birthday)}//提供Person实例的创建函数(Person类中的属性有val修饰,只能调用构造函数创建对象)fun build(): Person = Person(name, _birthday, address)//提供Address实例的创建函数fun address(block: AddressBuilder.() -> Unit) {address = AddressBuilder().apply(block).build()}
}class AddressBuilder {var street: String = ""var number: Int = 0var city: String = ""fun build(): Address = Address(street, number, city)
}fun person(block: PersonBuilder.() -> Unit): Person = PersonBuilder().apply(block).build()val person = person {name = "John"birthday = "2000-10-01"address {street = "Main Street"number = 42city = "London"}
}
三、集合
当类中属性存在一个或多个值时(集合)。
3.1 并行添加
data class Person(private val addresses: List<Address>
)data class Address(val street: String
)class PersonBuilder {private val addresses = mutableListOf<Address>()fun address(block: AddressBuilder.() -> Unit) {addresses.add(AddressBuilder().apply(block).build()) //往集合中添加新地址}fun build(): Person = Person(addresses.toList()) //将集合传递给构造
}class AddressBuilder {var street: String = ""fun build(): Address = Address(street)
}fun person(block: PersonBuilder.() -> Unit): Person = PersonBuilder().apply(block).build()val person = person {//一个人有多个地址(并行添加)address {street = "八一路"}address {street = "人民路"}
}
3.2 合并添加
data class Person(private val addresses: List<Address>
)data class Address(val street: String
)class PersonBuilder {private val addresses = mutableListOf<Address>()fun addresses(block: ADDRESS_LIST.() -> Unit) = addresses.addAll(ADDRESS_LIST().apply(block))fun build(): Person = Person(addresses)
}class AddressBuilder {var street: String = ""fun build(): Address = Address(street)
}//自定义List类,全大写强调是一个辅助类,将在SDL中不可见,实现一个很好的结构。
class ADDRESS_LIST : ArrayList<Address>() {fun address(block: AddressBuilder.() -> Unit) {add(AddressBuilder().apply(block).build()) //往自身添加Address对象}
}fun person(block: PersonBuilder.() -> Unit): Person = PersonBuilder().apply(block).build()val person = person {//一个人有多个地址(合并添加)addresses {address {street = "八一路"}address {street = "人民路"}}
}
四、缩小作用域 @DslMarker
由于嵌套的原因,我们可以调用 Lambda 内部每个可用的隐式接收者的函数,因此最终可能不是得到预期的结果。Kotlin v1.1 开始可以通过 @DslMaker 注解来避免这种情况,这时编译器就知道哪些隐式接收者是同一个DSL的一部分,只允许调用最近层的接收者成员。(想要的话仍可以使用显示接收者 this@person.name="李四")
val person = person { //this:PersonBuildername = "张三"addresses { //this:ADDRESS_LISTaddress { //this:AddressBuildername = "李四"}}
}
println(person.name) //打印:李四
//应用到一个自定义的注释类,然后注释那些DSL类
@DslMarker
annotation class PersonDSL
//除了类,把函数都加上
@PersonDSL
class PersonBuilder {...}
@PersonDSL
class AddressBuilder {...}
@PersonDSL
class ADDRESS_LIST : ArrayList<Address>() {...}
Kotlin - DSL相关推荐
- Spring Webflux: Kotlin DSL [片断]
原文链接:https://dzone.com/articles/spring-webflux-kotlin-dsl-snippets 作者:Biju Kunjummen 译者:Jackie Tang ...
- kotlin dsl_Spring Webflux – Kotlin DSL –实现的演练
kotlin dsl 在以前的博客文章中,我描述了Spring Web Framework中的响应式编程支持Spring Webflux如何使用基于Kotlin的DSL使用户能够以非常直观的方式描述路 ...
- Spring Webflux – Kotlin DSL –实现的演练
在先前的博客文章中,我描述了Spring Web Framework中的响应式编程支持Spring Webflux如何使用基于Kotlin的DSL使用户能够以非常直观的方式描述路由. 在这里,我想探索 ...
- gradle kotlin_我对Gradle Kotlin DSL的第一印象
gradle kotlin by Adam Arold 亚当·阿罗德(Adam Arold) 我对Gradle Kotlin DSL的第一印象 (My first impressions of Gra ...
- 《Kotin 极简教程》第14章 使用 Kotlin DSL
第14章 使用 Kotlin DSL 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: Kotlin 极简教程 htt ...
- Kotlin/DSL(Anko),原汁原味Kotlin开发Android---Activity Fragment与AnkoUI分离,强大的复用,更加便捷的开发
/写在前面 翻开自己的CSDN,已经很久很久没有活动了,最近的关于PDF签章的博客还是16年写的.将近年关,工作内容阶段性告一段落,终于有时间写一下自己的东西. 废话少说,说说Kotlin.kotli ...
- Kotlin | DSL
Kotlin DSL构建布局 文章目录 Kotlin DSL构建布局 前言 一.What's the DSL? 二.初探 1.DSL常见的应用 三.koltin中的DSL 1.扩展函数 2.带接收者的 ...
- 像 Compose 那样写代码 :Kotlin DSL 原理与实战
1. 前言 Kotlin 是一门对 DSL 友好的语言,它的许多语法特性有助于 DSL 的打造,提升特定场景下代码的可读性和安全性.本文将带你了解 Kotlin DSL 的一般实现步骤,以及如何通过 ...
- Kotlin DSL
DSL 简述 相比于传统 API,DSL 更符合人类的语言习惯. Domain Specific Language,专注于特定问题领域的计算机语言. DSL 只是问题解决方案模型的外部封装,这个模型可 ...
- Kotlin DSL 学习
之前在<Effective Kotlin> 一书中,有一条专门讲解 DSL 的:考虑为复杂的对象创建定义 DSL,让我对 DSL 有了一定的了解. 为了能够更熟悉掌握Kotlin上的DSL ...
最新文章
- linux进程间通信:POSIX 共享内存
- 成就解锁:BCH修复了所有常见的第三方交易延展性矢量
- WinForm界面开发之 启动界面
- 计算机组成原理——概述1
- html引入avalon,avalon中文文档
- java filter函数的用法_5分钟掌握Python | Map、Reduce和Filter如何运用?
- android 4种动画
- maven项目pom中scope类型
- 加拿大程序员趣闻系列 1/N
- python还是java好找工作_你觉得学 Python 还是 Java 更好找工作?
- 再谈shell之“/dev/null 21”
- native8081端口 react_教你轻松修改React Native的端口(如何同时运行多个React Native、8081端口占用问题)...
- IIS中发布网站的问题
- [国家集训队]跳跳棋
- 梯形图如何实现c语言 f语句,如何注释梯形图
- iphone用什么蓝牙耳机好?和iphone适配的蓝牙耳机推荐
- 学习AngularJS摘抄的笔记,方便以后查看(摘自菜鸟教程)
- 京东轮播图片的静态页面CSS3
- 游戏类型英文简称/全称对照表
- Beta Distribution Guided Aspect-aware Graph for Aspect Category Sentiment Analysis论文阅读笔记(EMNLP2021)
热门文章
- COleDateTime和COleDateTimeSpan类详细分析
- 基于若依开发物品管理系统(springboot+vue)
- R16开发板tina系统LCD调试
- ubuntu安装及使用教程
- [附源码]java毕业设计大学城二手书交易网站
- 【起】Redis 概述篇——带你走过 Redis 的前世今生
- SpringBoot----[9]---Spring Boot JdbcTemplate
- 中国石油大学(北京)-《石油加工工程》第二阶段在线作业
- OracleP6机场工程进度控制系列10:总进度计划编制基础
- 数学与计算机科学学院翻译,学院与专业英语翻译