Skip to content

Commit 1ae4f8e

Browse files
committed
《select 表达式》格式校对
1 parent 6b36974 commit 1ae4f8e

File tree

1 file changed

+88
-66
lines changed

1 file changed

+88
-66
lines changed

docs/select-expression.md

+88-66
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
<!--- INCLUDE .*/example-([a-z]+)-([0-9a-z]+)\.kt
22
/*
3-
43
* Copyright 2016-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
54
*/
65
@@ -17,6 +16,9 @@ import org.junit.Test
1716
class SelectGuideTest {
1817
-->
1918

19+
20+
## 目录
21+
2022
<!--- TOC -->
2123

2224
* [select 表达式(试验性)](#select-expression-experimental)
@@ -30,11 +32,14 @@ class SelectGuideTest {
3032

3133

3234

33-
## select 表达式(试验性
35+
## select 表达式(实验性的
3436

35-
select 表达式可以同时等待多个挂起函数,并 _选择_ 第一个可用的。
37+
select 表达式可以同时等待多个挂起函数,并_选择_<!--
38+
-->第一个可用的。
3639

37-
> Select 表达式是 `kotlinx.coroutines` 的试验性功能。它们的 API 在 `kotlinx.coroutines` 库即将到来的更新中可能会有很大的变化。
40+
> Select 表达式在 `kotlinx.coroutines` 中是一个实验性的特性。这些API在<!--
41+
--> `kotlinx.coroutines` 库即将到来的更新中可能会<!--
42+
-->发生改变。
3843
3944
### 从通道中查询
4045

@@ -44,48 +49,50 @@ select 表达式可以同时等待多个挂起函数,并 _选择_ 第一个可
4449

4550
```kotlin
4651
fun CoroutineScope.fizz() = produce<String> {
47-
while (true) { // sends "Fizz" every 300 ms
52+
while (true) { // 每 300ms 发送 "Fizz"
4853
delay(300)
4954
send("Fizz")
5055
}
5156
}
5257
```
5358

54-
59+
</div>
5560

5661
接着 `buzz` 每500毫秒产出 “Buzz!” 字符串:
5762

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

6065
```kotlin
6166
fun CoroutineScope.buzz() = produce<String> {
62-
while (true) { // sends "Buzz!" every 500 ms
67+
while (true) { // 每 500ms 发送 "Buzz!"
6368
delay(500)
6469
send("Buzz!")
6570
}
6671
}
6772
```
6873

74+
</div>
6975

70-
71-
使用 [receive][ReceiveChannel.receive] 挂起函数,我们可以从一个或另一个通道接收数据。但是 [select] 表达式允许我们使用其 [onReceive][ReceiveChannel.onReceive] 子句同时从两者接收:
76+
使用 [receive][ReceiveChannel.receive] 挂起函数,我们可以从一个或另一个通道接收数据。<!--
77+
-->但是 [select] 表达式允许我们使用其<!--
78+
--> [onReceive][ReceiveChannel.onReceive] 子句_同时_从两者接收:
7279

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

7582
```kotlin
7683
suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
77-
select<Unit> { // <Unit> means that this select expression does not produce any result
78-
fizz.onReceive { value -> // this is the first select clause
84+
select<Unit> { // <Unit> 意味着该 select 表达式不返回任何结果
85+
fizz.onReceive { value -> // 这是第一个 select 子句
7986
println("fizz -> '$value'")
8087
}
81-
buzz.onReceive { value -> // this is the second select clause
88+
buzz.onReceive { value -> // 这是第二个 select 子句
8289
println("buzz -> '$value'")
8390
}
8491
}
8592
}
8693
```
8794

88-
95+
</div>
8996

9097
让我们运行7次:
9198

@@ -99,25 +106,25 @@ import kotlinx.coroutines.channels.*
99106
import kotlinx.coroutines.selects.*
100107

101108
fun CoroutineScope.fizz() = produce<String> {
102-
while (true) { // sends "Fizz" every 300 ms
109+
while (true) { // 每 300ms 发送 "Fizz"
103110
delay(300)
104111
send("Fizz")
105112
}
106113
}
107114

108115
fun CoroutineScope.buzz() = produce<String> {
109-
while (true) { // sends "Buzz!" every 500 ms
116+
while (true) { // 每 500ms 发送 "Buzz!"
110117
delay(500)
111118
send("Buzz!")
112119
}
113120
}
114121

115122
suspend fun selectFizzBuzz(fizz: ReceiveChannel<String>, buzz: ReceiveChannel<String>) {
116-
select<Unit> { // <Unit> means that this select expression does not produce any result
117-
fizz.onReceive { value -> // this is the first select clause
123+
select<Unit> { // <Unit> 意味着该 select 表达式不返回任何结果
124+
fizz.onReceive { value -> // 这是第一个 select 子句
118125
println("fizz -> '$value'")
119126
}
120-
buzz.onReceive { value -> // this is the second select clause
127+
buzz.onReceive { value -> // 这是第二个 select 子句
121128
println("buzz -> '$value'")
122129
}
123130
}
@@ -130,7 +137,7 @@ fun main() = runBlocking<Unit> {
130137
repeat(7) {
131138
selectFizzBuzz(fizz, buzz)
132139
}
133-
coroutineContext.cancelChildren() // cancel fizz & buzz coroutines
140+
coroutineContext.cancelChildren() // 取消 fizz buzz 协程
134141
//sampleEnd
135142
}
136143
```
@@ -155,7 +162,10 @@ buzz -> 'Buzz!'
155162

156163
### 从关闭的通道查询
157164

158-
select 中的 [onReceive][ReceiveChannel.onReceive] 子句在已经关闭的通道会失败,并导致相应的 `select` 抛出异常。我们可以使用 [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] 子句在关闭通道时执行特定操作。以下示例还显示了 `select` 是一个返回其查询方法结果的表达式:
165+
select 中的 [onReceive][ReceiveChannel.onReceive] 子句执行在已经关闭的通道会失败,并导致相应的 <!--
166+
-->`select` 抛出异常。我们可以使用 [onReceiveOrNull][ReceiveChannel.onReceiveOrNull] 子句在关闭通道时执行<!--
167+
-->特定操作。以下示例还显示了 `select` 是一个返回<!--
168+
-->其查询方法结果的表达式:
159169

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

@@ -179,7 +189,8 @@ suspend fun selectAorB(a: ReceiveChannel<String>, b: ReceiveChannel<String>): St
179189

180190
</div>
181191

182-
现在有一个产出四次 “Hello” 字符串的 `a` 通道、一个产出四次 “World” 字符串的 `b` 通道,我们在这两个通道上使用它:
192+
现在有一个生成四次 “Hello” 字符串的 `a` 通道,<!--
193+
-->和一个产出四次 “World” 字符串的 `b` 通道,我们在这两个通道上使用它:
183194

184195
<!--- CLEAR -->
185196

@@ -214,7 +225,7 @@ fun main() = runBlocking<Unit> {
214225
val b = produce<String> {
215226
repeat(4) { send("World $it") }
216227
}
217-
repeat(8) { // print first eight results
228+
repeat(8) { // 打印最早的8个结果
218229
println(selectAorB(a, b))
219230
}
220231
coroutineContext.cancelChildren()
@@ -243,27 +254,31 @@ Channel 'a' is closed
243254

244255
有几个结果可以通过观察得出。
245256

246-
首先,`select` 偏向于第一个子句,当可以同时选到多个子句时,第一个子句将被选中。在这里,两个通道都在不断地生成字符串,因此作为 select 中的第一个子句的通道获胜。然而因为我们使用的是无缓冲通道,所以 `a` 在其发送调用时会不时被挂起,进而 `b` 也有机会发送。
247-
248-
第二个观察结果是,当通道已经关闭时,会立即选择 [onReceiveOrNull][ReceiveChannel.onReceiveOrNull]
249-
257+
首先,`select` _偏向于_第一个子句,当可以同时选到多个子句时,<!--
258+
-->第一个子句将被选中。在这里,两个通道都在不断地生成字符串,因此 `a` 通道<!--
259+
-->作为 select 中的第一个子句获胜。然而因为我们使用的是无缓冲通道,所以 `a` 在其调用 <!--
260+
-->[send][SendChannel.send] 时会不时地被挂起,进而 `b` 也有机会发送。
250261

262+
第二个观察结果是,当通道已经关闭时,<!--
263+
-->会立即选择 [onReceiveOrNull][ReceiveChannel.onReceiveOrNull]
251264

252265
### 查询并发送
253266

254-
Select 表达式具有 [onSend][SendChannel.onSend] 子句,可以很好的与选择的偏向特性结合使用。
267+
Select 表达式具有 [onSend][SendChannel.onSend] 子句,可以很好的与<!--
268+
-->选择的偏向特性结合使用。
255269

256-
我们来编写一个整数生成器的示例,当主通道上的消费者无法跟上它时,它会将值发送到 `side` 通道上:
270+
我们来编写一个整数生成器的示例,当主通道上的<!--
271+
-->消费者无法跟上它时,它会将值发送到 `side` 通道上:
257272

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

260275
```kotlin
261276
fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
262-
for (num in 1..10) { // produce 10 numbers from 1 to 10
263-
delay(100) // every 100 ms
277+
for (num in 1..10) { // 生产从 1 到 10 的10个数值
278+
delay(100) // 100 ms
264279
select<Unit> {
265-
onSend(num) {} // Send to the primary channel
266-
side.onSend(num) {} // or to the side channel
280+
onSend(num) {} // 发送到主通道
281+
side.onSend(num) {} // 或者发送到 side 通道
267282
}
268283
}
269284
}
@@ -283,24 +298,24 @@ import kotlinx.coroutines.channels.*
283298
import kotlinx.coroutines.selects.*
284299

285300
fun CoroutineScope.produceNumbers(side: SendChannel<Int>) = produce<Int> {
286-
for (num in 1..10) { // produce 10 numbers from 1 to 10
287-
delay(100) // every 100 ms
301+
for (num in 1..10) { // 生产从 1 到 10 的10个数值
302+
delay(100) // 100 ms
288303
select<Unit> {
289-
onSend(num) {} // Send to the primary channel
290-
side.onSend(num) {} // or to the side channel
304+
onSend(num) {} // 发送到主通道
305+
side.onSend(num) {} // 或者发送到 side 通道
291306
}
292307
}
293308
}
294309

295310
fun main() = runBlocking<Unit> {
296311
//sampleStart
297-
val side = Channel<Int>() // allocate side channel
298-
launch { // this is a very fast consumer for the side channel
312+
val side = Channel<Int>() // 分配 side channel
313+
launch { // 对于 side 通道来说,这是一个很快的消费者
299314
side.consumeEach { println("Side channel has $it") }
300315
}
301316
produceNumbers(side).consumeEach {
302317
println("Consuming $it")
303-
delay(250) // let us digest the consumed number properly, do not hurry
318+
delay(250) // 让我们不急切地、适当地来消费数值
304319
}
305320
println("Done consuming")
306321
coroutineContext.cancelChildren()
@@ -332,7 +347,9 @@ Done consuming
332347

333348
### 查询延迟值
334349

335-
延迟值可以使用 [onAwait][Deferred.onAwait] 子句查询。让我们启动一个延迟随机时间后返回延迟字符串的异步方法:
350+
延迟值可以使用 [onAwait][Deferred.onAwait] 子句查询。<!--
351+
-->让我们启动一个异步函数,它在<!--
352+
-->随机的延迟后会返回延迟字符串:
336353

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

@@ -358,7 +375,10 @@ fun CoroutineScope.asyncStringsList(): List<Deferred<String>> {
358375

359376
</div>
360377

361-
现在主函数等待第一个函数完成,并统计仍处于激活状态的延迟值的数量。注意,我们在这里的使用,事实上是把 `select` 表达式作为一种Kotlin DSL,所以我们可以用任意代码为它提供子句。在这种情况下,我们遍历一个延迟值的队列,为每个延迟值提供 `onAwait` 子句。
378+
现在主函数在等待第一个函数完成,并统计仍处于<!--
379+
-->激活状态的延迟值的数量。注意,我们在这里的使用,事实上是把 `select` 表达式作为一种Kotlin DSL,<!--
380+
-->所以我们可以用任意代码为它提供子句。在这种情况下,我们遍历一个<!--
381+
-->延迟值的队列,并为每个延迟值提供 `onAwait` 子句。
362382

363383
<!--- CLEAR -->
364384

@@ -411,26 +431,28 @@ Deferred 4 produced answer 'Waited for 128 ms'
411431

412432
### 在延迟值通道上切换
413433

414-
我们现在来编写一个通道生产者函数,它消费一个产生延迟字符串的通道,并等待每个接收的延迟值,但只在下一个延迟值到达或者通道关闭之前。此示例将 [onReceiveOrNull][ReceiveChannel.onReceiveOrNull][onAwait][Deferred.onAwait] 子句放在同一个 `select` 中:
434+
我们现在来编写一个通道生产者函数,它消费一个产生延迟字符串的通道,并等待每个接收的<!--
435+
-->延迟值,但只在下一个延迟值到达或者通道关闭之前。此示例将 <!--
436+
-->[onReceiveOrNull][ReceiveChannel.onReceiveOrNull][onAwait][Deferred.onAwait] 子句放在同一个 `select` 中:
415437

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

418440
```kotlin
419441
fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
420-
var current = input.receive() // start with first received deferred value
421-
while (isActive) { // loop while not cancelled/closed
422-
val next = select<Deferred<String>?> { // return next deferred value from this select or null
442+
var current = input.receive() // 从第一个接收到的延迟值开始
443+
while (isActive) { // 循环直到被取消或关闭
444+
val next = select<Deferred<String>?> { // 从这个 select 中返回下一个延迟值或 null
423445
input.onReceiveOrNull { update ->
424-
update // replaces next value to wait
446+
update // 替换下一个要等待的值
425447
}
426448
current.onAwait { value ->
427-
send(value) // send value that current deferred has produced
428-
input.receiveOrNull() // and use the next deferred from the input channel
449+
send(value) // 发送当前延迟生成的值
450+
input.receiveOrNull() // 然后使用从输入通道得到的下一个延迟值
429451
}
430452
}
431453
if (next == null) {
432454
println("Channel was closed")
433-
break // out of loop
455+
break // 跳出循环
434456
} else {
435457
current = next
436458
}
@@ -454,7 +476,8 @@ fun CoroutineScope.asyncString(str: String, time: Long) = async {
454476

455477
</div>
456478

457-
主函数只是启动一个协程来打印 `switchMapDeferreds` 的结果并向它发送一些测试数据:
479+
主函数只是启动一个协程来打印 `switchMapDeferreds` 的结果并向它发送一些<!--
480+
-->测试数据:
458481

459482
<!--- CLEAR -->
460483

@@ -466,20 +489,20 @@ import kotlinx.coroutines.channels.*
466489
import kotlinx.coroutines.selects.*
467490

468491
fun CoroutineScope.switchMapDeferreds(input: ReceiveChannel<Deferred<String>>) = produce<String> {
469-
var current = input.receive() // start with first received deferred value
470-
while (isActive) { // loop while not cancelled/closed
471-
val next = select<Deferred<String>?> { // return next deferred value from this select or null
492+
var current = input.receive() // 从第一个接收到的延迟值开始
493+
while (isActive) { // 循环直到被取消或关闭
494+
val next = select<Deferred<String>?> { // 从这个 select 中返回下一个延迟值或 null
472495
input.onReceiveOrNull { update ->
473-
update // replaces next value to wait
496+
update // 替换下一个要等待的值
474497
}
475498
current.onAwait { value ->
476-
send(value) // send value that current deferred has produced
477-
input.receiveOrNull() // and use the next deferred from the input channel
499+
send(value) // 发送当前延迟生成的值
500+
input.receiveOrNull() // 然后使用从输入通道得到的下一个延迟值
478501
}
479502
}
480503
if (next == null) {
481504
println("Channel was closed")
482-
break // out of loop
505+
break // 跳出循环
483506
} else {
484507
current = next
485508
}
@@ -494,20 +517,20 @@ fun CoroutineScope.asyncString(str: String, time: Long) = async {
494517
fun main() = runBlocking<Unit> {
495518
//sampleStart
496519
val chan = Channel<Deferred<String>>() // the channel for test
497-
launch { // launch printing coroutine
520+
launch { // 启动打印协程
498521
for (s in switchMapDeferreds(chan))
499-
println(s) // print each received string
522+
println(s) // 打印每个获得的字符串
500523
}
501524
chan.send(asyncString("BEGIN", 100))
502-
delay(200) // enough time for "BEGIN" to be produced
525+
delay(200) // 充足的时间来生产 "BEGIN"
503526
chan.send(asyncString("Slow", 500))
504-
delay(100) // not enough time to produce slow
527+
delay(100) // 不充足的时间来生产 "Slow"
505528
chan.send(asyncString("Replace", 100))
506-
delay(500) // give it time before the last one
529+
delay(500) // 在最后一个前给它一点时间
507530
chan.send(asyncString("END", 500))
508-
delay(1000) // give it time to process
509-
chan.close() // close the channel ...
510-
delay(500) // and wait some time to let it finish
531+
delay(1000) // 给执行一段时间
532+
chan.close() // 关闭通道……
533+
delay(500) // 然后等待一段时间来让它结束
511534
//sampleEnd
512535
}
513536
```
@@ -529,7 +552,6 @@ Channel was closed
529552

530553
<!--- MODULE kotlinx-coroutines-core -->
531554
<!--- INDEX kotlinx.coroutines -->
532-
533555
[Deferred.onAwait]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-deferred/on-await.html
534556
<!--- INDEX kotlinx.coroutines.channels -->
535557
[ReceiveChannel.receive]: https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.channels/-receive-channel/receive.html

0 commit comments

Comments
 (0)