语法糖是什么
根据百度百科的词语释义,语法糖(Syntactic Sugar) ,也称糖衣语法。是由英国计算机科学家彼得·约翰·兰达(Peter J. Landin)发明的一个术语,指的是在计算机语言中添加的某种语法,这种语法对语言的编译结果和功能并没有实际影响, 但是却能更方便程序员使用该语言。
个人理解概况就是:通过编程语言的特性方法快捷实现某些复合的代码逻辑,本篇内粗糙理解为语法特性
本篇记录一些常见的kotlin语法糖,以备不时之需
语法糖列举
域函数
即对象调用本函数时,可以在对应的函数体内(中括号内)形成一个作用域,不带对象名称或者it/this而调用到对象本身,示例:
Person("Alice", 20, "Amsterdam").let {
println(it)
it.moveTo("London")
it.incrementAge()
println(it)
}
这样的作用域函数有五个,对应区别为
作用域函数 | 对象引用方式 | 返回值 |
---|---|---|
run | this | lambdab表达式结果 |
let | it | lambdab表达式结果 |
with | this | lambdab表达式结果 |
apply | this | 对象本身 |
also | it | 对象本身 |
第一反应是:有啥意义啊?不差这一个对象名调用吧就
- 一个可能是根据作用域语法来收束单个对象的调用逻辑,提升代码可读性,避免东一棒子西一榔头的调用,相关代码的关联性不够。
- 一个是函数本身自带结果,可以作为代码逻辑的一部分,使得代码非常简化(个人是没理解到这个感觉是增加可读复杂性的效果,可能熟练了就理解到了)
多了解一点
五个域函数的源码:
@kotlin.internal.InlineOnly
public inline fun <T, R> T.run(block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block()
}
```
@kotlin.internal.InlineOnly
public inline fun <T, R> with(receiver: T, block: T.() -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return receiver.block()
}
```
```
@kotlin.internal.InlineOnly
public inline fun <T> T.apply(block: T.() -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block()
return this
}
```
```
@kotlin.internal.InlineOnly
@SinceKotlin("1.1")
public inline fun <T> T.also(block: (T) -> Unit): T {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
block(this)
return this
}
```
```
@kotlin.internal.InlineOnly
public inline fun <T, R> T.let(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
return block(this)
}
```
以最后的also为例子
于是可知道
- run/apply/let/also通过泛型的扩展函数都是通过对象调用的,with需要单独传对象进去,而run还可以单独括号执行一段逻辑并返回结果
- apply和also都是返回调用对象自己的值,其他都返回代码块的结果
- also和let传入的block是(T)的类型,于是引用的时候可以直接有it代指,如果此时代码块用this,那就会指向外部声明方法的类。run/apply/with传入的block都是T.()即为泛型T的扩展函数,没有实际对象,所以没有it的语法,需要使用this来引用
数据类
通过data关键字声明class,直接在类名后的括号内(即默认的构造函数)声明成员变量,除了普通声明也有的变量声明为val的话就默认自带getter,声明为var默认自带setter和getter,data class会自动生成:
- equals/hashcode方法,比较值而不是比较引用
- toString方法,调用直接输出String内容即每个变量的值
- copy方法,对数据类对象的浅拷贝
- componentN,N按照参数数量按顺序生成
所以最大的方便就是直接声明完类名往括号里扔对应的参数后就可以不用管(常规这种bean类成员变量特别多,对应get/set和toString非常繁琐冗杂),后续可以直接进行这种bean类的get/set与toString了
单例类
究极方便的一个单例语法糖,类关键字class都不用,直接object+名称即可得到一个单例,自然而然反编译可以看到具体实现
可以看到是一个通过静态代码块对静态对象进行的赋值,在类的加载过程就进行了赋值的方式确保的线程安全,即所谓的饿汉式单例
扩展函数
在已有的类里添加方法,通过方法名前面声明类名.的形式可以实现该效果。自然而然,反编译看看源码实现逻辑
可以看到,实际上在扩展函数声明后是通过声明对应方法后传入调用对象作为扩展函数的参数,再调用后续逻辑的。大多数情况扩展函数作为顶层函数声明,则会成为一个静态方法