go 没有 future,标准库不提供 future/promise 及其链式方法;第三方封装用 channel+goroutine 带来类型擦除、隐式 goroutine、panic 和错误传播断裂等问题;原生 make(chan t, 1) 是最简、安全、编译器可检的“future”实现。

Go 里没有 Future,别写 func() *Future
Go 标准库不提供 Future 或 Promise 类型,也没有 .Then()、.Catch() 这类方法。你看到的第三方包(比如 samber/mo 或 gofuture)本质是用 channel + goroutine 包了一层函数式外壳,但代价明显:类型擦除、隐式 goroutine、重复 close 导致 panic: send on closed channel、错误传播链断裂。真实项目里,这类封装往往在压测时暴露竞态,在超时场景下漏 cancel,还让新人误以为“channel 可以反复读取”。你要的只是「启动异步任务,稍后取结果」——原生方式更短、更稳、编译器还能帮你检查方向性。
make(chan T, 1) 是最简 Future 的物理载体
返回一个带缓冲的只读 channel(),就是 Go 中最自然的 Future 表达。它不是模拟,是并发模型的直接映射:
- 缓冲大小必须为
1:确保 goroutine 启动后能立刻写入,不因接收方还没执行就卡死 - 类型必须带
error字段,例如struct{ v User; err error }:避免多 channel 同步,也防止成功/失败路径分裂 - 绝不在函数体里
close(ch),而是在 goroutine 内defer close(ch):让接收方能通过val, ok := 判断是否已送达,而非靠零值猜状态 - 不要返回
chan interface{}:编译期丢失类型,.v.Name这种访问会在运行时报错
加 context.Context 才算完整 Future 语义
裸 channel 不支持取消、超时、父子传递。真正生产可用的“异步结果句柄”,得把 context.Context 塞进 goroutine:
- 启动 goroutine 时传入
ctx,并在关键阻塞点(如http.Get、db.Query)检查ctx.Err() - select 等待结果时,必须包含
case 分支,且要处理 <code>ctx.Err()是context.Canceled还是context.DeadlineExceeded - 别用额外的 cancel channel 去“通知 goroutine 停下”:Go 没有抢占式取消,必须靠函数内部主动轮询
ctx.Done() - 如果任务已结束但 channel 还没被读,
ctx被 cancel 不会自动关 channel——这是设计使然,接收方仍需自己处理val, ok
多个异步任务怎么“并行等全部完成”
Go 没有 Promise.all(),但也不需要它。惯用做法是组合 sync.WaitGroup 和结果 channel:
- 每个子任务返回
,启动时 <code>wg.Add(1),goroutine 结束前wg.Done() - 开一个 collector goroutine,for range 从每个
读取(channel 关闭后 range 自动退出) - 用切片收集结果,最后统一返回;若任一出错,可提前关闭 collector channel 并 return
- 别用
select { case r1 := 写死分支:动态数量任务无法扩展,且 select 随机选就绪 case,不能保证顺序
最容易被忽略的是 channel 方向性: 和 <code>chan 是编译期强制约束。写反了,比如在只该发送的地方尝试接收,Go 直接报错——这不是限制,是你在调用现场就被拦下的 Future 误用证据。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











