<commit_before>---
type: doc
layout: reference
title: "Kotlin 1.3 的新特性"
---

# Kotlin 1.3 的新特性

## 协程正式发布

历经了漫长而充足的的测试，协程终于正式发布了！这意味着自 Kotlin 1.3 起，协程的语言支持与 API 已[完全稳定](evolution/components-stability.html)。参见新版[协程概述](coroutines-overview.html)。

Kotlin 1.3 引入了挂起函数的可调用引用以及在反射 API 中对协程的支持。

## Kotlin/Native

Kotlin 1.3 继续改进与完善原生平台。详情请参见 [Kotlin/Native 概述](native-overview.html)。

## 多平台项目

在 1.3 中，我们完全修改了多平台项目的模型，以提高表现力与灵活性，并使共享公共代码更加容易。此外，多平台项目现在也支持 Kotlin/Native！

与旧版模型的主要区别在于：

  * 在旧版模型中，需要将公共代码与平台相关代码分别放在独立的模块中，以 `expectedBy` 依赖项链接。
    现在，公共代码与平台相关代码放在相同模块的不同源根（source root）中，使项目更易于配置。
  * 对于不同的已支持平台，现在有大量的[预设的平台配置](building-mpp-with-gradle.html#supported-platforms)。
  * 更改了[依赖配置](building-mpp-with-gradle.html#adding-dependencies)；现在为每个源根分别指定依赖项。
  * 源集（source set）现在可以在任意平台子集之间共享（例如，在一个目标平台为 JS、Android 与 iOS 的模块中，可以有一个只在 Android 与 iOS 之间共享的源集）。
  * 现在支持[发布多平台库](building-mpp-with-gradle.html#publishing-a-multiplatform-library)了。

更多相关信息，请参考[多平台程序设计文档](multiplatform.html)。

## 契约

Kotlin 编译器会做大量的静态分析工作，以提供警告并减少模版代码。其中最显著的特性之一就是智能转换——能够根据类型检测自动转换类型。

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun foo(s: String?) {
    if (s != null) s.length // 编译器自动将“s”转换为“String”
}
```

</div>

然而，一旦将这些检测提取到单独的函数中，所有智能转换都立即消失了：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun String?.isNotNull(): Boolean = this != null

fun foo(s: String?) {
    if (s.isNotNull()) s.length // 没有智能转换 :(
}
```

</div>

为了改善在此类场景中的行为，Kotlin 1.3 引入了称为 *契约* 的实验性机制。

*契约* 让一个函数能够以编译器理解的方式显式描述其行为。目前支持两大类场景：

- 通过声明函数调用的结果与所传参数值之间的关系来改进智能转换分析：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun require(condition: Boolean) {
    // 这是一种语法格式，告诉编译器：
    // “如果这个函数成功返回，那么传入的‘condition’为 true”
    contract { returns() implies condition }
    if (!condition) throw IllegalArgumentException(...)
}

fun foo(s: String?) {
    require(s is String)
    // s 在这里智能转换为“String”，因为否则
    // “require”会抛出异常
}
```

</div>

-  在存在高阶函数的情况下改进变量初始化的分析：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun synchronize(lock: Any?, block: () -> Unit) {
    // 告诉编译器：
    // “这个函数会在此时此处调用‘block’，并且刚好只调用一次”
    contract { callsInPlace(block, EXACTLY_ONCE) }
}

fun foo() {
    val x: Int
    synchronize(lock) {
        x = 42 // 编译器知道传给“synchronize”的 lambda 表达式刚好
               // 只调了一次，因此不会报重复赋值错
    }
    println(x) // 编译器知道一定会调用该 lambda 表达式而执行
               // 初始化操作，因此可以认为“x”在这里已初始化
}
```

</div>

### 标准库中的契约

`stdlib（kotlin 标准库）`已经在利用**契约**这一特性，改善了上述情景中代码分析情况。这一部分的契约功能已经趋于稳定，意味着你不需要任何额外的操作就可以享用改善后的代码分析。

<div class="sample" data-min-compiler-version="1.3" markdown="1" theme="idea">

```kotlin
//sampleStart
fun bar(x: String?) {
    if (!x.isNullOrEmpty()) {
        println("length of '$x' is ${x.length}") // 看，智能地向非空类型转换！
    }
}
//sampleEnd
fun main() {
    bar(null)
    bar("42")
}
```

</div>

### 自定义契约

你也可以为你自己的函数来自定义契约，但是这一功能目前还是**实验性**的，因为目前的契约语法尚处于早期的原型态，很有可能在后面的版本被修改。而且，值得注意的是，目前 Kotlin 的编译器并没有对契约进行验证，所以需要开发者编写正确稳定的契约。

自定义契约通过调用标准库中的 `contract` 函数来引入，这个函数提供了 DSL：
<commit_msg>校对《1.3 的新特性》“标准库中的契约”一节<commit_after>---
type: doc
layout: reference
title: "Kotlin 1.3 的新特性"
---

# Kotlin 1.3 的新特性

## 协程正式发布

历经了漫长而充足的的测试，协程终于正式发布了！这意味着自 Kotlin 1.3 起，协程的语言支持与 API 已[完全稳定](evolution/components-stability.html)。参见新版[协程概述](coroutines-overview.html)。

Kotlin 1.3 引入了挂起函数的可调用引用以及在反射 API 中对协程的支持。

## Kotlin/Native

Kotlin 1.3 继续改进与完善原生平台。详情请参见 [Kotlin/Native 概述](native-overview.html)。

## 多平台项目

在 1.3 中，我们完全修改了多平台项目的模型，以提高表现力与灵活性，并使共享公共代码更加容易。此外，多平台项目现在也支持 Kotlin/Native！

与旧版模型的主要区别在于：

  * 在旧版模型中，需要将公共代码与平台相关代码分别放在独立的模块中，以 `expectedBy` 依赖项链接。
    现在，公共代码与平台相关代码放在相同模块的不同源根（source root）中，使项目更易于配置。
  * 对于不同的已支持平台，现在有大量的[预设的平台配置](building-mpp-with-gradle.html#supported-platforms)。
  * 更改了[依赖配置](building-mpp-with-gradle.html#adding-dependencies)；现在为每个源根分别指定依赖项。
  * 源集（source set）现在可以在任意平台子集之间共享（例如，在一个目标平台为 JS、Android 与 iOS 的模块中，可以有一个只在 Android 与 iOS 之间共享的源集）。
  * 现在支持[发布多平台库](building-mpp-with-gradle.html#publishing-a-multiplatform-library)了。

更多相关信息，请参考[多平台程序设计文档](multiplatform.html)。

## 契约

Kotlin 编译器会做大量的静态分析工作，以提供警告并减少模版代码。其中最显著的特性之一就是智能转换——能够根据类型检测自动转换类型。

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun foo(s: String?) {
    if (s != null) s.length // 编译器自动将“s”转换为“String”
}
```

</div>

然而，一旦将这些检测提取到单独的函数中，所有智能转换都立即消失了：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun String?.isNotNull(): Boolean = this != null

fun foo(s: String?) {
    if (s.isNotNull()) s.length // 没有智能转换 :(
}
```

</div>

为了改善在此类场景中的行为，Kotlin 1.3 引入了称为 *契约* 的实验性机制。

*契约* 让一个函数能够以编译器理解的方式显式描述其行为。目前支持两大类场景：

- 通过声明函数调用的结果与所传参数值之间的关系来改进智能转换分析：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun require(condition: Boolean) {
    // 这是一种语法格式，告诉编译器：
    // “如果这个函数成功返回，那么传入的‘condition’为 true”
    contract { returns() implies condition }
    if (!condition) throw IllegalArgumentException(...)
}

fun foo(s: String?) {
    require(s is String)
    // s 在这里智能转换为“String”，因为否则
    // “require”会抛出异常
}
```

</div>

-  在存在高阶函数的情况下改进变量初始化的分析：

<div class="sample" markdown="1" theme="idea" data-highlight-only>

```kotlin
fun synchronize(lock: Any?, block: () -> Unit) {
    // 告诉编译器：
    // “这个函数会在此时此处调用‘block’，并且刚好只调用一次”
    contract { callsInPlace(block, EXACTLY_ONCE) }
}

fun foo() {
    val x: Int
    synchronize(lock) {
        x = 42 // 编译器知道传给“synchronize”的 lambda 表达式刚好
               // 只调了一次，因此不会报重复赋值错
    }
    println(x) // 编译器知道一定会调用该 lambda 表达式而执行
               // 初始化操作，因此可以认为“x”在这里已初始化
}
```

</div>

### 标准库中的契约

`stdlib`（kotlin 标准库）已经利用契约带来了如上所述的对代码分析的改进。这部分契约是**稳定版的**，这意味着你现在就可以从改进的代码分析中受益，而无需任何额外的 opt-ins：

<div class="sample" data-min-compiler-version="1.3" markdown="1" theme="idea">

```kotlin
//sampleStart
fun bar(x: String?) {
    if (!x.isNullOrEmpty()) {
        println("length of '$x' is ${x.length}") // 哇，已经智能转换为非空！
    }
}
//sampleEnd
fun main() {
    bar(null)
    bar("42")
}
```

</div>

### 自定义契约

你也可以为你自己的函数来自定义契约，但是这一功能目前还是**实验性**的，因为目前的契约语法尚处于早期的原型态，很有可能在后面的版本被修改。而且，值得注意的是，目前 Kotlin 的编译器并没有对契约进行验证，所以需要开发者编写正确稳定的契约。

自定义契约通过调用标准库中的 `contract` 函数来引入，这个函数提供了 DSL：

{'fraction_non_alphanumeric': 0.15703942075623492, 'fraction_numerical': 0.0083668543845535, 'mean_word_length': 4.656050955414012, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4132621', 'n_tokens_mistral': 3823, 'n_tokens_neox': 4232, 'n_words': 404}