跳至主要內容
yomihon 書庫
整體狀況設定

鍵盤快捷鍵

⌘K / Ctrl K
搜尋
Esc
關閉搜尋或篩選
/
跳到導覽篩選(單鍵開啟時)
[
收合或展開側欄(單鍵開啟時)

關掉之後,/ 和 [ 都只會照瀏覽器原本的方式輸入;⌘K 與 Esc 不受影響。

設定
esc

↑↓ 選擇 ↵ 搜尋 esc 關閉

G03 關閉 channel

lesson檔案變更於
檔案變更於
類型
lesson
語言
zh-Hant
在 Obsidian 開啟留下自己的想法
檔案變更於
類型
lesson
語言
zh-Hant
在 Obsidian 開啟留下自己的想法
本頁內容 以這篇為來源的筆記 1 對照閱讀 1 正文連到這篇 2

收到一個值之後,接收者還需要知道:後面是否有下一個?close(ch) 宣告不會再發送;for value := range ch 會接收剩餘值,直到 channel 關閉且已取空。1

package main

import "fmt"

func squares() <-chan int {
	out := make(chan int, 3)
	go func() {
		defer close(out)
		for _, n := range []int{1, 2, 3} {
			out <- n * n
		}
	}()
	return out
}

func main() {
	values := squares()
	for value := range values {
		fmt.Println(value)
	}
	value, ok := <-values
	fmt.Println(value, ok)
}

關閉會丟掉尚未接收的值嗎?

假設 producer 在 main 開始接收前就完成了迴圈,range 還能拿到三個值嗎?最後一行又會印什麼?

查看輸出與解析

三個值仍然在緩衝區。單一 producer 依序送入,所以輸出固定是:

1
4
9
0 false

最後一次接收時,channel 已關閉且取空,得到 int 的零值與 ok == false。若收到的是 producer 真正送出的 0,ok 仍是 true。

誰能確定不會再發送?

本例只有一個 producer,由它在最後一次發送後關閉 out。接收者若自行關閉,producer 之後再發送就會 panic;重複關閉也會 panic。1

拿掉 defer close(out),前三個值仍會出現,但 range 會繼續等第四個值。若只有一次交接,雙方也知道次數,則未必需要關閉;關閉是結束訊號,不是每個 channel 都要執行的清理動作。

多個 producer 共用一個輸出時,必須先等全部停止發送,再由一處關閉。G05 固定數量的 worker 會用到這個安排。

channel 的交接

concept檔案變更於
檔案變更於
類型
concept
語言
zh-Hant
在 Obsidian 開啟留下自己的想法
檔案變更於
類型
concept
語言
zh-Hant
在 Obsidian 開啟留下自己的想法
聲明的來源 2 正文連到這篇 4
操作 何時能繼續
無緩衝 channel 的 send 有接收方配對時
有緩衝 channel 的 send 緩衝區有空位時
receive 有值可取,或 channel 已關閉時
向 nil channel send/receive 永遠阻塞

close(ch) 表示不再送值。已緩衝的值仍可取出;取完後,v, ok := <-ch 得到零值與 false。向已關閉的 channel 送值會 panic。

關閉前,必須確定所有 send 都已結束。單一 producer 可以自行關閉;多個 worker 共用輸出時,由等待所有 worker 的協調者關閉。

Go 規格:Channel types(另開分頁)、Close(另開分頁)