根据KotlinConf的消息,Kotlin1.4会在2020年发布。其中除了很多跨平台能力的补强之外,也有不少语法层面的改进,可能会对广大开发者带来更直接的影响
Kotlin支持SAM转换
SAM的意思是Singel Abstract Method,我们将只有单一方法的接口/抽象类成为SamType。Kotlin目前(最新1.3.6)仅能支持Java中的SAM转换
//java
public interface OnClickListener {
void onClick(View v);
}
public class View {
public void setOnClickListener(@Nullable OnClickListener l) {
mOnClickListener = l
}
}
//kt
view.setOnClickListener( object : OnClickListener {
override fun onClick(v: View) {
...
}
})
// SAM转换
view.setOnClickListener {
...
}
Kotlin通过SAM转换可以将Java中对SamType的调用,转换为一个对Lambda的调用,减少大量的模板代码,但是同样SamType如果定义在Kotlin中,是无法转换的
interface Action {
fun run()
}
fun runAction(a: Action) = a.run()
fun main() {
runAction {
// error :Type mismatch.
// Required: Action
// Found: () → Unit
...
}
}
但是在1.4之后,可以通过为interface添加fun关键字, 声明为SamType,
fun interface Action {
fun run()
}
fun main() {
runAction {
println("Hello, KotlinConf!")
}
}
即使在1.4之前,我们也有一些SAM转换的替代方案,详细可以参考这篇文 https://blog.csdn.net/vitaviva/article/details/104055623
混用命名参数和位置参数
Kotlin进行方法调用时可以通过参数名指定参数,也可以不指定,按照声明的顺序传参
fun f(a: Int, b: Int, c: Int) {}
fun main() {
f(1, 2, 3) //位置传参:按序传参
f(a = 1, c = 3, b = 2) //命名传参:按参数名传参
}
但是不允许混合两种
fun main() {
f(1, b = 2, 3) // Mixing named and positioned arguments is not allowed
}
1.4之后允许上面这种传参方式,这样参数过多的调用时可以提高代码可读性。
尾后逗号
当函数的参数比较多时,为了可读性,我们习惯换行书写:
fun f(
a: Int,
b: Int,
c: Int, //error: Expecting an argument
)
data class Item(
val a: Int,
val b: Int,
val c: Int, //error: Expecting an argument
)
此时,如果需要增加参数或者交换位置时,总要额外删除最后一个参数尾部的逗号,1.4之后允许尾后逗号的存在,方便修改。
属性代理优化
我们自定义属性代理时,为了能够在调用getValue/setValue时获取KProperty,Kotlin在编译期会生成一个$$delegatedProperties数组,用来存储所有可能用到KProperty
//定义代理
class Delegate {
lateinit var real : String
operator fun getValue(thisRef: Any?, property: KProperty<*>): String {
return real
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: String) {
println("${property.name}: $value")
real = value
}
//使用代理
class MyClass {
var s by Delegat {"hello"}
s = "hello kotlin"
}
反编译java后会发现多了$$delegatedProperties
public final class MyClass {
static final kotlin.reflect.KProperty[] $$delegatedProperties; //存储KProperty
...
KProperty var2 = $$delegatedProperties[0];
s.setValue((Object)null, var2, "hello kotlin");
}
但很多时候我们不使用KProperty,此时没有必要生成$$delegatedProperties。Kotlin1.4优化了这种case,如果我们在operator前加inline,且使用KProperty的话,就不回再生成$$delegatedProperties。例如 未来1.4中lazy的代理定义如下
//定义
inline operator fun <T> Lazy<T>.getValue(
thisRef: Any?, property: KProperty<*>): T = value
反编译的Java将不会再生成$$delegatedProperties。