当 Go 的 channel 被 close 后读写操作会怎么样?

当 Go 的 channel 被 close 后,对它的读操作行为有以下明确规则:


重点行为总结

操作 行为
从已关闭且仍有缓存数据的 channel 读 会正常返回该数据
从已关闭且缓冲区数据已读完的 channel 读 返回 零值 (基于类型)和 ok=false
向已关闭的 channel 写数据 ❌ 直接 panic

如果 channel 没有缓冲 和有缓冲的读完数据后的操作是一样的结果


示例代码

go 复制代码
ch := make(chan int, 2)
ch <- 1
ch <- 2
close(ch)

v, ok := <-ch // v=1, ok=true
v, ok = <-ch // v=2, ok=true
v, ok = <-ch // v=0, ok=false

range 遍历已关闭 channel

当你使用 range 遍历 channel 时,它会一直读到 channel 关闭且数据读完后才退出循环:

go 复制代码
for v := range ch {
    fmt.Println(v)
}
fmt.Println("done")

零值返回示例

如果 channel 是 chan string,零值读出来就是 ""

如果是 chan *User,零值就是 nil


为什么要设计成这样?

  • 避免读端阻塞
  • 让接收端可以用 ok 判断数据是否结束
  • 使 channel 更像是一个有限流(stream)

典型使用场景

生产者关闭 channel 通知消费者不再有新数据

go 复制代码
func producer(out chan<- int) {
    defer close(out)
    for i := 0; i < 5; i++ {
        out <- i
    }
}

func consumer(in <-chan int) {
    for v := range in {
        fmt.Println(v)
    }
}

常见误区

误区 实际情况
close 后读会 panic ❌ 永远不会 panic
必须由接收方 close ❌ 通常是发送方 close
close 可重复调用 ❌ 重复 close 会 panic

完整示例代码

go 复制代码
package main

import (
    "fmt"
)

func main() {
    ch := make(chan int, 3)

    // Producer
    go func() {
        for i := 0; i < 5; i++ {
            ch <- i
        }
        close(ch) // 通知消费者:不再有新数据
    }()

    // Consumer
    for v := range ch { // 会一直读到 ch 被关闭 & 数据读完
        fmt.Println("received:", v)
    }

    fmt.Println("done") // 会执行,因为 range 自动退出
}

输出示例(顺序可能不同)

sh 复制代码
received: 0
received: 1
received: 2
received: 3
received: 4
done
相关推荐
wuyk5555 小时前
第2章:六步换相原理全解+STM32工程实战
c语言·开发语言·stm32·单片机·嵌入式硬件
hey_sml5 小时前
JAVA每日一学---CompletableFuture中thenApply与thenCompose区别详解
java·开发语言
维克兜率天6 小时前
【维克】ARMA模型:AR与MA的完美结合
后端·restful
萧瑟余晖6 小时前
Java深入解析篇十七之SpringCloud
java·开发语言
是未才7 小时前
从输入 URL 到页面返回:DNS、路由、TLS 与 HTTP 完整链路
java·后端·计算机网络
上海安当技术7 小时前
半天接入:USBKey RESTful API + C 动态库,Web 和 C/S 两套集成路径实战
前端·后端·restful·集成·usbkey
ttod_qzstudio7 小时前
Java 常用语法极简通关(五):类与对象——字段、方法、构造器、this 与 static
java·开发语言·python
DevUI团队7 小时前
从“即兴创作”到“规格先行”,华为云码道(CodeArts)代码智能体持续深耕企业级规范驱动开发能力
前端·人工智能·后端
萧瑟余晖8 小时前
Java深入解析篇十七之Spring Security
java·开发语言·spring
weixin_431600448 小时前
NestJS 入门(3):Guard 如何挡住未登录请求?
前端·后端·学习·nest.js