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相关推荐

  1. Spring Webflux: Kotlin DSL [片断]

    原文链接:https://dzone.com/articles/spring-webflux-kotlin-dsl-snippets 作者:Biju Kunjummen 译者:Jackie Tang ...

  2. kotlin dsl_Spring Webflux – Kotlin DSL –实现的演练

    kotlin dsl 在以前的博客文章中,我描述了Spring Web Framework中的响应式编程支持Spring Webflux如何使用基于Kotlin的DSL使用户能够以非常直观的方式描述路 ...

  3. Spring Webflux – Kotlin DSL –实现的演练

    在先前的博客文章中,我描述了Spring Web Framework中的响应式编程支持Spring Webflux如何使用基于Kotlin的DSL使用户能够以非常直观的方式描述路由. 在这里,我想探索 ...

  4. gradle kotlin_我对Gradle Kotlin DSL的第一印象

    gradle kotlin by Adam Arold 亚当·阿罗德(Adam Arold) 我对Gradle Kotlin DSL的第一印象 (My first impressions of Gra ...

  5. 《Kotin 极简教程》第14章 使用 Kotlin DSL

    第14章 使用 Kotlin DSL 最新上架!!!< Kotlin极简教程> 陈光剑 (机械工业出版社) 可直接打开京东,淘宝,当当===> 搜索: Kotlin 极简教程 htt ...

  6. Kotlin/DSL(Anko),原汁原味Kotlin开发Android---Activity Fragment与AnkoUI分离,强大的复用,更加便捷的开发

    /写在前面 翻开自己的CSDN,已经很久很久没有活动了,最近的关于PDF签章的博客还是16年写的.将近年关,工作内容阶段性告一段落,终于有时间写一下自己的东西. 废话少说,说说Kotlin.kotli ...

  7. Kotlin | DSL

    Kotlin DSL构建布局 文章目录 Kotlin DSL构建布局 前言 一.What's the DSL? 二.初探 1.DSL常见的应用 三.koltin中的DSL 1.扩展函数 2.带接收者的 ...

  8. 像 Compose 那样写代码 :Kotlin DSL 原理与实战

    1. 前言 Kotlin 是一门对 DSL 友好的语言,它的许多语法特性有助于 DSL 的打造,提升特定场景下代码的可读性和安全性.本文将带你了解 Kotlin DSL 的一般实现步骤,以及如何通过 ...

  9. Kotlin DSL

    DSL 简述 相比于传统 API,DSL 更符合人类的语言习惯. Domain Specific Language,专注于特定问题领域的计算机语言. DSL 只是问题解决方案模型的外部封装,这个模型可 ...

  10. Kotlin DSL 学习

    之前在<Effective Kotlin> 一书中,有一条专门讲解 DSL 的:考虑为复杂的对象创建定义 DSL,让我对 DSL 有了一定的了解. 为了能够更熟悉掌握Kotlin上的DSL ...

最新文章

  1. linux进程间通信:POSIX 共享内存
  2. 成就解锁:BCH修复了所有常见的第三方交易延展性矢量
  3. WinForm界面开发之 启动界面
  4. 计算机组成原理——概述1
  5. html引入avalon,avalon中文文档
  6. java filter函数的用法_5分钟掌握Python | Map、Reduce和Filter如何运用?
  7. android 4种动画
  8. maven项目pom中scope类型
  9. 加拿大程序员趣闻系列 1/N
  10. python还是java好找工作_你觉得学 Python 还是 Java 更好找工作?
  11. 再谈shell之“/dev/null 21”
  12. native8081端口 react_教你轻松修改React Native的端口(如何同时运行多个React Native、8081端口占用问题)...
  13. IIS中发布网站的问题
  14. [国家集训队]跳跳棋
  15. 梯形图如何实现c语言 f语句,如何注释梯形图
  16. iphone用什么蓝牙耳机好?和iphone适配的蓝牙耳机推荐
  17. 学习AngularJS摘抄的笔记,方便以后查看(摘自菜鸟教程)
  18. 京东轮播图片的静态页面CSS3
  19. 游戏类型英文简称/全称对照表
  20. Beta Distribution Guided Aspect-aware Graph for Aspect Category Sentiment Analysis论文阅读笔记(EMNLP2021)

热门文章

  1. COleDateTime和COleDateTimeSpan类详细分析
  2. 基于若依开发物品管理系统(springboot+vue)
  3. R16开发板tina系统LCD调试
  4. ubuntu安装及使用教程
  5. [附源码]java毕业设计大学城二手书交易网站
  6. 【起】Redis 概述篇——带你走过 Redis 的前世今生
  7. SpringBoot----[9]---Spring Boot JdbcTemplate
  8. 中国石油大学(北京)-《石油加工工程》第二阶段在线作业
  9. OracleP6机场工程进度控制系列10:总进度计划编制基础
  10. 数学与计算机科学学院翻译,学院与专业英语翻译