现在我们非常自豪地发布 Kotlin 1.3-RC,这将是 1.3 之前的最后一个预览版本。这个版本修复了绝大多数的新功能相关的关键 bug,除此之外,还有一些其他的更新值得一提:
- Ktor 的 API 已经完善,期待大家的使用体验和反馈。Ktor 是一个基于协程的框架,使用它我们可以优雅的构建 Web 应用、Http 服务、移动应用和网页。
- 所有的新项目都已经采用官方代码规范 ,我们也非常鼓励大家也这样做。
- 程序入口
main函数支持无参数的形式,它也可以是一个 suspend 函数。 - 1.2.50 引进的对脚本的支持如今也得到了更新和完善。
-
kotlinx.serialization的插件已经合入 Kotlin 主工程,并且被集成到编译器插件当中。 - 我们废弃了一些标准库当中的 API,当然对于过去就已经废弃的 API 这次我们直接报错。
-
org.jetbrains.annotations当中的注解从标准库中独立出来,成为一个新的构件方便开发者自由选择依赖。
感谢来自社区的贡献者们,这个版本合入了以下开发者的代码提交:Toshiaki Kameyama, Cuihtlauac ALVARADO, kenji tomita, Martin Petrov, Denis Vnukov, shiraji, Paul de Vrieze, Raluca Sauciuc, Ivan Gavrilovic.
完整的更新内容请参见 更新日志。
如果您在试用 1.3 版本的新功能和特性时遇到了问题,请及时与我们联系,我们非常期待和感谢您的反馈。Kotlin 1.3.0 的最终版本即将到来,请抓紧时间分享您的使用体验吧!
2018 Kotlin 开发者大会
Kotlin 开发者大会即将召开!对于不方便现场参加大会的开发者,我们将提供现场直播以及资料共享。请您 注册 以便得到我们的直播通知。
是时候迁移您的协程代码了
从 Kotlin 1.3 开始,协程将进入稳定状态。鉴于此,大家可以在 1.3.0 发布之后就可以立刻马上迁移协程代码了,我们也会提供相应的工具帮助大家完成这项工作。
对于kotlinx.coroutines 来说:
- 您需要在实验状态下(experimental) 更新到最新的版本,当前最新版是 0.26.1(Kotlin 1.3 发布之前也可能会有少量的更新)
- 将您的项目直接切换到 Kotlin 1.3,IDE 的工具会帮助您完成迁移,目前来说就是切换到 0.26.1-eap13,这个版本是基于 Kotlin 1.3 构建的。这个迁移工作主要是去掉包名当中的 experimental。
- 待 Kotlin 1.3 正式发版之后,
kotlinx.coroutines也将会发布 1.0 版,届时您只需要更新版本号,重新编译代码即可。
需要注意的是,kotlinx.coroutines 1.0 将会丢弃所有之前的 0.x 版本中的废弃的接口和声明,与 0.x-eap13 版本二进制不兼容,因此在切换正式版之前就需要把您代码中使用过时 API 的代码进行整理。
kotlinx.coroutines也会有一些 API 被标记为“unstable”,它们将会在后续的更新中得到完善。尽管使用这些“unstable”的 API 需要特定的选项配置,但核心 API 都将在 1.0 最终确定并保证如同 Kotlin 标准库一样在后续更新中后向兼容。
不需要参数的 “Main” 函数
就像其他很多语言那样,我们从 1.3 开始允许 “main” 函数的字符串数组参数可选,如此一来,经典的 “Hello, World!” 在 Kotlin 当中就更短啦:
fun main() {
println("Hello, World!")
}
可挂起的 “main” 函数
“main”函数不仅参数可选,还可以是 “suspend”,换句话说,您再也不需要使用 “runBlocking” 就可以在 “main”函数当中直接调用其他 “suspend” 函数了:
import kotlinx.coroutines.*
//sampleStart
suspend fun main() = coroutineScope {
val task1 = async { fetchResult(id = 42) }
val task2 = async { fetchResult(id = 99) }
val results = awaitAll(task1, task2)
log(results)
}
//sampleEnd
suspend fun fetchResult(id: Int): String {
log("started request #$id")
delay(500)
return "result #$id"
}
val startedAt = System.currentTimeMillis()
fun elapsed() = System.currentTimeMillis() - startedAt
fun log(message: Any) = println("At ${elapsed()} ms: $message")
Ktor 框架
协程终于“毕业”,所以妈妈再也不用担心我们发布我们自己的异步框架了。为此,我们做了很多工作,其中最值得一提的是 Ktor –
一个用于连接应用的异步框架。它包括一个跨平台的 HTTP 客户端和一个基于 JVM 的 HTTP 服务端。
客户端目前已经支持 JVM/Android 和 iOS,后续也将支持更多的平台包括 JS(浏览器)和各种各样的 native 平台。服务端则运行在 JVM 上面,您可以使用 Netty、Jetty 以及其他类似于 Tomcat 的 servlet 容器。
Ktor 测试充分、易于上手、性能优越,请参考 ktor.io/。它的 0.9.5-rc13 兼容 Kotlin 1.3-RC,0.9.5 则兼容 Kotlin 1.2.70。
与我们一起打造我们自己的异步框架吧,这样我们就可以让我们的代码可读性和可维护性得到飞跃!
编码规范
官方代码规范文档已经推出了一些时日,是时候做进一步的工作了:从 Kotlin 1.3 开始,使用 IntelliJ IDEA 创建的所有新项目都将应用这份代码规范。
虽然我们建议大家通过提交 .idea/codeStyles 到 VCS 来共享代码风格,但不少开发者的内心却是拒绝的。因此我们引入了一个 Gradle 的属性 kotlin.code.style,可以设置值为 official 或 obsolete。如此一来,其他 IDE 也就可以享受到这一特性了。
如果您想要使用原来的代码风格,只需要设置 kotlin.code.style=obsolete以免后续遇到迁移上的麻烦。这个属性在 Maven 当中也适用。
脚本
这个版本对脚本的支持做了很多优化改进,其中最重要的就是重新打造的更简洁更清爽的 API。尽管脚本支持的特性可能还需要一段时间的实验,但目前看来 API 将基本定型。其中的一些无用的和尚未实现的 API 被移除,等时机成熟,在后续的版本当中我们有意对绝大多数移除的 API 进行召回。
为了简化脚本项目的构建和工具脚本的依赖,我们提供了一个新的组件 kotlin-main-kts。这个简单的 jar 包提供了一些脚本的定义和基本的 Maven 构建解析器,有了它,我们就可以写出下面的脚本了:
@file:Repository("https://jcenter.bintray.com")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-html-jvm:0.6.11")
import kotlinx.html.*
import kotlinx.html.stream.*
print(createHTML().html {
body {
h1 { +"Hello, World!" }
}
})
运行时只需要将 kotlin-main-kts.jar 添加到 classpath:
kotlinc -cp <path/to/kotlin-main-kts.jar> -script sample.main.kts
脚本支持方面还有其他的许多问题修复和功能提升,建议大家通过案例多多尝试,并积极反馈~
完整的 Kotlin 脚本提案以及当前的实现状态可以参考 KEEP-75。
实验状态的序列化插件
从这个版本开始,以前独立的插件 kotlinx.serialization 将合并到 Kotlin 的编译器插件当中。
尽管在 Kotlin 1.3 当中它将仍然保持实验状态,但这并不影响它在生产环境中的使用,它是足够成熟和稳定的,我们也非常期待大家的反馈。相关提案请参见:KEEP-149,如果有什么意见和建议,欢迎开 issue 讨论。
内联类 Inline classes
我们调整了内联类的二进制表示,目的是让它更加紧凑、更与时俱进,同时也修复了一些关键的问题。Kotlin 反射也可以正确的处理内联类,并完成自动的拆箱和装箱。
标准库
相比之下,这个版本更关注正式发版前的代码整理而不是新功能。
可空类型的 hashCode()
当实现一个泛型容器类时,通常我们需要获取元素的哈希值,而元素通常也可以为 null,因此过去我们需要使用 ?. 以及 elvis 运算符来解决这个问题:
element?.hashCode() ?: 0.
现在我们有了 Any?.hashCode(),对于任意元素无论是否为空,都可以如此调用: element.hashCode()。
Range 迭代时的元素空检查
在 value 是可空类型,同时 Range 是 Iterable且范围较大时,在 value in from..to 中进行空检查将非常耗时。这种情况下,范围的包含关系判断会退化成 Iterable<T>.contains(T),这样整个过程就成了 Iterable 的遍历(直到元素找到或者确定找不到为止)。
为了解决这个问题,我们引入了一系列 contains 的重载,以 IntRange.contains(element: Int?) 为例,它会先检查参数 element 是否为空,紧接着执行一个快速的包含关系判断:
class IntRange(start: Int, endInclusive: Int) : IntProgression(start, endInclusive, 1), ClosedRange<Int> {
...
override fun contains(value: Int): Boolean = first ≤ value && value ≤ last
...
}
@SinceKotlin("1.3")
public inline operator fun IntRange.contains(element: Int?): Boolean {
return element != null && contains(element)
}
SuccessOrFailure 更名为 Result
我们在之前的 Kotlin 1.3 预览版中提供了一个封装 Kotlin 函数结果的类 SuccessOrFailure,经过 review 和社区反馈,更名为Result。这个类目前主要应用于协程,作为Continuation.resumeWith的参数。Kotlin 中有许多设计线索可用于将来扩展错误处理,这将要求我们重新设计使用此Result类作为返回类型的代码的语义。因此,为避免将来的设计会破坏此类代码,Kotlin
1.3 编译器会对于这类声明报错,当然标准库函数的一些情况则是例外,因为这些函数专门用于对 Result 类型进行操作。详细请参见 KEEP-127。
Sequence 和 iterator 的创建函数以及他们的 scope 类
在协程 API 最终确定下来之前,我们需要对 buildSequence 和 buildIterator 进行重命名。这些名字主要是为了与 buildString 以及一些构造集合框架类型的函数提议保持一致。然而,我们最近意识到 sequence 和 string 的创建函数在懒加载方面差异较大,所谓的一致性实际上并不是很合理。
这些创建函数从 buildSequence { } 和 buildIterator { } 更名为 sequence { } 和 iterator { }。参数的 receiver 类则从 SequenceBuilder 变更为 SequenceScope。
这样一来,Sequence 的创建代码将变成:
import kotlinx.coroutines.*
//sampleStart
fun idCandidates(baseId: String): Sequence<String> = sequence {
yield(baseId)
for (suffix in 'a'..'z') {
yield(baseId + "-" + suffix)
}
}
//sampleEnd
fun main() {
idCandidates("base-id").take(10).forEach(::println)
}
有符号整型转无符号时符号位扩展到长整型
整型有符号到无符号转换的处理方法与其他语言趋于一致,Int.toULong() 以及其他类似的函数在转换时采用了符号位扩展到高位的做法,而不是 0 扩展,所以 (-1).toULong() 现在等于 ULong.MAX_VALUE (0xFFFF_FFFF_FFFF_FFFF) 而不是 UInt.MAX_VALUE (0x0000_0000_FFFF_FFFF).
注解成为独立的构件
与编译器一起发布的标准库不再包含 org.jetbrains.annotations 中的注解,这样也可以与 Maven Central 中发布的标准库保持一致。这些注解现可以在 annotations-13.0.jar 和 mutability-annotations-compat.jar 当中找到。
废弃整型、浮点型混合的区间包含运算符
前面我们提到对于可空类型的包含关系判断会有问题,其实还有一个麻烦就是整型区间遇到浮点型参数这样类似的情况。例如 3.14 in 1..3 是可以编译运行的,但结果就有点儿尴尬了: true。我们废弃了这样的 contains 运算符重载,后面会逐渐移除它们。
其他废弃的通知
对于过去就已经废弃的 API,这次我们会提高它们的废弃级别,对于使用这些 API 的代码,我们会直接报错而不是警告。
这版要对 JS 标准库中曾经废弃的 API 下手的主要有:
jsClass函数kotlin.Synchronized和Volatile注解kotlin.js.Math函数kotlin-test-js当中org.junit.Test注解
如果这些您都不熟,那没关系。否则的话,请尽快按照说明迁移您的代码。
在下一个版本也就是 1.4 当中,我们将要移除标准库当中的 jQuery 类型的声明,相应的功能将由 https://bintray.com/kotlin/js-externals/kotlin-js-jquery 提供。
命令行编译器
这一版本支持我们选用另外的一种方式来通过文件给编译器传参。除了使用 1.2.50 中引入的 -Xargfile=filename.txt,您也可以直接给 kotlinc 传入 @filename.txt 这样的参数,文件内容将会被按行解析为参数。这样将会方便使用 kotlinc 编译大量的源文件,同时也可以方便处理更长更复杂的文件路径。
这版中另一个要“毕业的”的实验特性便是 1.2.50 引入的 progressive 编译模式,我们可以通过 -progressive 来打开这种模式。
如何尝鲜
在 Maven/Gradle 项目中: 为构建脚本和项目依赖添加 repository https://dl.bintray.com/kotlin/kotlin-eap。使用 1.3.0-rc-57 作为编译器和标准库的版本号。
在 IntelliJ IDEA 中: 在 Tools → Kotlin → Configure Kotlin Plugin Updates中,Update channel 中选择 “Early Access Preview 1.3”,然后点击Check for updates。
命令行编译器可以在 Github release page 下载。
在 try.kotlinlang.org上: 在右下角的下拉列表中选择编译器的版本为 1.3‑RC 即可。