Kotlin团队的大牛Roman Relizarov在最近的一个演讲中,分享了Kotlin团队是如何收集、提炼用户需求、并最终落地成型的过程。其中举的几个case,都是呼声很高且有可能真正落地的语法,值得一看。
https://youtu.be/0FF19HJDqMo
YouTrack&KEEP
Kotlin团队通过YouTrack收集和跟踪来自开发者们的各种Issue,其中一些准入的Issue会进入KEEP进行管理。很多YouTrack的Issue初衷虽好,但以为不符合语言设计习惯等原因,经过不断讨论和演进,以一个最佳姿态落地成型。本文介绍的几个case也是经历了如此的演进过程,并有可能在未来的版本中出现
Namespace
KT-11968:有开发者提议通过Companion
关键字,为Java类可扩展地定义静态方法/变量:
val android.content.Intent.Companion.SCHEME_SMS:String get() = "sms"
这样可以在Java中实现静态调用
Intent.SCHEME_SMS
这个本质上是一个对namespace
的需求。Kotlin鼓励使用top-level function替代Util类,但有时我们希望提供类似namespace
的机制方便我们索引这些方法,常见的做法是定义object
类后充当静态方法使用:Delegates.notNull()
,这无形会增加一个obejct对象的创建,如果新增一个namespace
关键字,则可以漂亮的解决类似问题
//KT-11968
val Delegates.Companion.notNull() = ...
⬇️⬇️
//NOW
object Delegates {
fun <T : Any> notNull(): ...
// other declarations
}
⬇️⬇️
//Maybe in FUTURE
namespace Delegates {
fun <T : Any> notNull(): ...
// other declarations
}
Multiple receivers
KT-10468:例如在Android中,一个方法需要借助View和Float两个receiver,此时希望定义多receiver的扩展方法
fun (View, Float).dp() = this * resources.displayMetrics.density
// explicitly: fun (View, Float).dp() = this@Float * [email protected]
class SomeView : View {
val someDimension = 4f.dp()
}
现状我们是如何解决类似问题的呢?我们为了提供多个this
上下文时,一般使用with()
with(view) {
42f.dp()
}
with(...){ ... }
写起来嵌套过多,借鉴python等语言中,使用注解避免嵌套的的做法(decortor):
#python的decorator:
def hello(fn):
def wrapper():
print "hello, %s" % fn.__name__
fn()
print "goodby, %s" % fn.__name__
return wrapper
@hello
def foo():
print "i am foo"
因此是否可以结合注解decortor的方式,实现with(){}提供的receiver效果呢?
//KT-10468
fun (View, Float).dp() = this * resources.displayMetrics.density
⬇️⬇️
//NOW
with(view) {
42f.dp()
}
⬇️⬇️
//Maybe in FUTURE
@with<View>
fun Float.dp() = this * resources.displayMetrics.density
Public/Private property types
KT-14663:声明一个属性时,同时出现Public和Private修饰符
private val items = mutableListOf<Item>()
public get(): List<Item>
//or
val items = mutableListOf<Item>()
get(): List<Item>
日常开发时,我们希望一个属性,对外是一个抽象类型,对内是一个具体类型,
现状做法是像下面这样,声明两个属性:
private val _items = mutableListOf<Item>()
val item : List<Item> by _items
由于这个Issue非常自然和容易理解,无需过多干预和改变,已经具备落地的条件
Value Class
我们常用 data class
来代表immutable的数据,并使用copy通过生成副本进行update,以避免修改原data,造成diff的失效。
// 1. 定义data class
data class State(
val lastUpdate: Instant,
val tags: List<String>
)
// 2. 通过copy进行update
state = state.copy(
lastUpdate = now(),
tag = state.tags + tag
)
// 3. 使用
notifyOnChange(state)
但是当嵌套过深时,copy方法使用起来就非常麻烦了。当然有人会说可以将成员定义成var,直接修改,但是这会造成后续diff的实效
// 1. 定义data class
data class State(
var lastUpdate: Instant,
var tags: List<String>
)
// 2. 直接update
state.lastUpdate = now()
state.tags += tag
// 3. copy后使用
notifyOnChange(state.copy) //此时如果后续有diff逻辑,会失效
此时我们试图设计一种新的类型Value Class
,可以在update的同时生成副本,解决此类问题。
//val关键字定义class
val class State(
val lastUpdate: Instant,
val tags: List<String>
)
// update后,会产生副本
state.lastUpdate = now()
state.tags += tag
Summary
如果你喜欢Kotlin、关注并使用YouTrack、也许未来某个版本的Kotlin中就会出现你的想法。而你所做的贡献都会永久记录在YouTrack中。