当 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
相关推荐
东风破_11 小时前
danci 2:创建的单词书到底存在哪里?从 Supabase 一路理解 ORM、Drizzle 和 RLS
数据库·后端·node.js
CoderIsArt11 小时前
C#中UI 线程与 Dispatcher
开发语言·ui·c#
东风破_11 小时前
danci 项目(三):从 JSON 数据到 AI Coding,真实项目里的数据清洗、Prompt 和工程规范
前端·后端·node.js
东风破_12 小时前
danci 项目(一):从需求到架构,一个单词学习系统为什么会这样设计
前端·后端·node.js
jay神13 小时前
【计算机毕业设计】基于SpringBoot的程序教学辅助系统
java·前端·vue.js·spring boot·后端·毕业设计·课程设计
AI情绪识别开源13 小时前
检信 ALLEMOTION OS 加密打包可执行程序 — 全面测试报告版本: v1.3功能测试 / 性能测试 /
开发语言·数据结构·人工智能·功能测试
「QT(C++)开发工程师」14 小时前
C++ auto 用法详解
开发语言·c++
OPEN-F14 小时前
C++STL教程:容器适配器与实用工具
开发语言·c++
yaoxin52112314 小时前
507. Java 反射 - 在 BeanFactory 中实现依赖注入
java·开发语言