Kotlin 最近一直很低调,低调得我都快忘了它了。我这段时间观察 GitHub 和 Slack,猜测 Kotlin 现在的工作重心应该在扩展其使用场景——Jvm 当然是无法满足 Kotlin 的,JavaScript 也不能——Native 也许是现阶段的主战场。
从主线版本发布 1.2 以来,Kotlin Native 的发版节奏已经基本上赶上了主线的节奏,其中主线更新了 5个版本,Native 更新了 6 个。
跟前一段儿时间大家关注孟美岐是否能够 C 位出道一样,我每隔几天就要去翻一翻 Kotlin 的代码提交,博客,论坛,这段时间能获得的消息实在有限。所以 Slack 成了唯一能够让我们发现蛛丝马迹的地方。
前不久,有个开发者在 Native 的频道说,我们项目呐,在开发一个图像处理的引擎,现在用 Kotlin 开发的 Android 版本,将来也自然是要移植到 iOS 上;说到移植,那么就想要了解下 Kotlin Native 什么时候会有一个正式版或者稳定版出来?
后来,这事儿让 Native 项目的老大知道了——当然,他很快就知道了,我怀疑他的工作有一项很重要的内容,就是回复 Slack!——老大当时就表示:咳咳,这位兄dei,您是不是有哪些误解?我们 Native 现在的最新版本就是稳定的,可以用在生产环境当中。而 Native 1.0 之前我们要做的,主要是提升开发体验,完善 Gradle 插件以及平台兼容和交互;嗯,当然还有就是实现 Kotlin 1.3 的一些新特性,比如无符号类型。
所以,如果想要尝鲜 Kotlin Native 的童鞋,我觉得现在切入可以了,毕竟 iOS 开发工具(AppCode)都给你备齐了不是?
嗯?等等,刚才那位大哥,您说 Kooootlin 1.3?
频道里面另一位兄弟表示,哪里有 1.3 的消息?我们粉丝团怎么都不知道!
啊哈,这次,Kotlin Team 确实够低调,相关的消息并没有在任何官方的线上渠道发布出来。这就尴尬了,我们只能祭出爬楼的优秀身体素质,没关系,我们都是狗仔队!
在这位兄弟的疑惑下,有人贴出了某大佬的一次分享的 PPT,主要内容包括:
1.3 有一个让大家期待已久的点,那就是协程的“成人礼”,从 1.3 开始,协程相关的 Api 的包名都将去掉 'experimental' 的字样,当然老接口也会兼容到 1.4。
新版的 Kotlin 将支持 suspend
函数的引用,换句话说,我们之前的挂起函数是算不上完全意义上的“一等公民”的,例如下面的函数,我们就无法使用它的引用 ::hello
,这有点儿像 16 岁之前但大于 8岁的孩子是限制民事行为能力人一样。。。
suspend fun hello(){
}
除此之外,1.3 也会给我们带来一些协程性能上的提升,反正协程现在的版本已经是安全的钙,好喝的钙了,1.3 的协程大概就是新盖中盖。
不要骗我,我只听过内联函数,怎么还有内联类?
我们经常需要用一个类来包装一些值,实际上这样的类本身没有太多自己的功能——除了包装。内联类就可以帮我们在编译的时候把这些包装类给处理掉,这样它们就不会存在于内存当中了,经济实惠是吧。
当然这一个特性有些限制就是它必须有一个主构造器,并且只能有一个不可变的属性。
Java 是没有无符号类型的,但 Native 需要兼容的 C 语言神马的有无符号类型啊。不过,有了 inline class,无符号类型的实现似乎就自然多了,毕竟,一个无符号的整形和一个有符号的整形都占用相同大小的内存,是不是只需要包装下,再配合编译器处理下字面量,就妥妥的了?
这个功能对于很多特殊的场景还是比较有用的。
这个内容实际上很久之前雀雀就写过一篇文章:Kotlin Contracts DSL 专门介绍这个系统,不过那时候只能是猜测,还不能真正看到其实现的效果。
据说 1.3 这个功能就会上线,那时候 Kotlin 的智能转换或者说推断还能扩展到函数当中,图中 check
函数中的 contract
表示这个函数的正常返回意味着传入的参数是真,所以我们在外部就可以把 x
当做 String
来使用了。
这个特性有很多有趣的使用场景,例如:
val nullableValue: String? = ...
nullableValue.guard {
return // nullableValue 为空,直接返回
}
val int = nullableValue.toInt() //nullableValue 不为空
从目前看到的源码来看,我们似乎可以通过 callsInPlace
来实现 guard
这个扩展方法,这个实际上有点儿仿 swift 的 guard 的意思。
总之, contract
可以通过函数调用内部的一些逻辑判断来对外部的逻辑做出推断,这一点使得 Kotlin 的推断能力更强大,也更具扩展性。
类型推断是个强大的东西,但有时候推断的结果跟我们预想的不一致,就会比较蛋疼。而且,推断过度的话也会让人摸不着头脑,例如:
fun <T> Iterable<T>.fun2(item: T) = Unit
fun <T> fun3(iter: Iterable<T>, value: T) = Unit
fun main(args: Array<String>) {
val iterable: Iterable<String> = listOf("Hello", "World")
iterable.fun2(5)
fun3(iterable, 5)
}
这段代码是我在论坛上看到的,很有趣, fun2
的泛型参数类型 T
应该与 iterable
的实参 String
是一致的呀,可是它怎么能够允许传入一个 5
呢?不幸的是,它确实可以编译通过。这就尴尬了,也许我们发现了一个 Kotlin 的 bug?当然也不算是,毕竟, T
的类型你又没有明确说,人家这里按照 iterable
和实参和参数 5
的类型进行推断,结果 T
的类型被推断为 Any
。这让我想到了前一段时间提到的,分支中有可能是 Int
也可能是 Long
的情形,这时候结果类型就被推断为 Any
,可以参考:val b = a?: 0,a 是 Double 类型,那 b 是什么类型?。
总之类型推断有些情况下还是挺让人担心的——而 Kotlin 的理念一直就有一条:反对任何形式的隐式推断的行为。
瞧瞧吧,一个连 Int
隐式转换为 Long
类型都不能忍的语言,这回又要出招了:
这一批配送的当然还有 @Exactly
, @OnlyInputTypes
等,这些注解已经在标准库内部悄悄使用了,图中的 filterIsInstance
就是一个例子。
fun main(args: Array<String>) {
needStringArray(arrayOf(1,3, "hello",4).filterIsInstance<String>())
}
fun needStrings(strings: List<String>) = Unit
尽管我们知道我们需要的类型是 List<String>
,这一点从 needStrings
的参数就可以推断而来,但偏偏因为 NoInfer
的存在,我们不得不在 filterIsInstance
调用的地方明确写上泛型实参 String
,这就是 NoInfer
的作用。如果我们自己定义一个不用 NoInfer
修饰的方法:
public inline fun <reified R> Array<*>.filterIsInstance2(): List<R> {
return filterIsInstanceTo(ArrayList<R>())
}
那么前面的代码就可以改成:
needStringArray(arrayOf(1,3, "hello",4).filterIsInstance2()) //注意这时候就不需要泛型实参了
到底要不要推断,需要开发者自己体会。 @NoInfer
这样的注解大概就是接口开发者用来为调用者规避问题的良心设计了。
来说个大家都能开心的。
我们知道,如果一个方法的参数中,包含一个只有一个方法的 Java 接口,那么我们可以使用 SAM 来简化这个接口的实现,例如:
executor.submit{
...
}
Runnable {
...
}
但前面提到的几个条件任意一个不满足,对不起,不能用 SAM 了。于是乎,我们发现我们用 Kotlin 定义了一个函数:
fun needARunnable(runnable: Runnable){
...
}
想使用 Lambda 简化一下是不行的:
fun main(args: Array<String>) {
needARunnable {} // ERROR!!
}
万马奔腾
为什么?是自己人啊,咋 Kotlin 自己的代码还成了后娘养的?反正这事儿真是被大家吐槽吐够了,官方每次给出的答案都是大家可以用下 typealias
啊,接受一个函数类型的参数就好啦,但这样定义出来的接口在 Java 里面看起来又是怪怪的(类型是 FunctionN)。
好,那么,看来 1.3 要解决这个问题了,开心~
最后再说一个高大上的。这个冰冰可能会比较感兴趣,作为一个通信本硕毕业没有学过编译原理的我,看这个的感觉就是。。。尼玛。。。
IR 就是 Intermediate representation,可以理解为我们通常说的中间语言,Kotlin 现在在 Jvm 和 Js 上面的做法是分别编译成 Jvm 的字节码和 JavaScript 代码,那么有了自己的 IR 之后,就先统一生成中间代码,这样也能与 Kotlin Native 统一起来(后者现在已经使用了 IR)。据称这之后,比如我们常用的注解处理器完成的代码生成的工作也会有较大的变革,我理解是至少说三个平台的特性也会达成一致吧,这无论是对于使用者还是对于 Kotlin 官方的开发者来说,都是好消息。
反正,很牛逼就是了。
所有 Kotlin 1.3 相关特性的图片来自谷歌相册:Release and experimental features in Kotlin 1.3
当然公众号上面当然是看不到地址的,所以你们也别尝试去看了 :)
总之,1.3 还是值得期待的,还有 Kotlin Native 的 1.0 呢。那么问题来了,这些消息啥时候官方会有个正式的通知啊?或者说啥时候才能有个 1.3 preview?不好说,大约在冬季?
转载请注明出处:微信公众号 Kotlin