Go语言如何编写可接受任意类型通道的通用函数?
Go通用通道输入函数实现方案
错误原因
你遇到的编译错误是Go类型系统的正常表现:虽然任意类型都满足interface{}约束,但chan int、chan string这类具体元素类型的通道,和chan interface{}是完全独立的两种类型,不存在隐式转换规则,因此不能直接传入参数声明为chan interface{}的函数。
实现方案
方案1:Go 1.18+ 泛型实现(推荐)
Go 1.18版本引入的泛型是该需求的最优解,兼顾编译期类型安全和运行时性能,无额外开销,示例代码如下:
package main import "errors" // T是泛型参数,约束为任意类型,保证入参arg的类型和通道元素类型一致 func SendToChannel[T any](arg T, channel chan T) error { // 这里可以加非阻塞发送、超时判断等额外逻辑,示例简化处理 select { case channel <- arg: return nil default: return errors.New("通道已满,发送失败") } } func main() { IntChan := make(chan int, 1) StringChan := make(chan string, 1) // 直接传不同类型的通道即可,编译期自动校验类型匹配 SendToChannel(1, IntChan) SendToChannel("hello", StringChan) }
方案2:Go 1.18以前 反射实现(兼容旧版本)
如果必须兼容无泛型的旧版本Go,可以通过反射实现,缺点是类型校验只能在运行时执行,有额外性能开销,需要自己处理边界情况,示例代码如下:
package main import ( "errors" "fmt" "reflect" ) func SendToChannel(arg interface{}, channel interface{}) error { // 校验入参是否为通道类型 chVal := reflect.ValueOf(channel) if chVal.Kind() != reflect.Chan { return errors.New("第二个参数必须为通道类型") } // 校验通道是否支持写入 if chVal.Type().ChanDir()&reflect.SendDir == 0 { return errors.New("传入的通道为只读通道,不可写入") } // 校验参数类型和通道元素类型匹配 argVal := reflect.ValueOf(arg) if !argVal.Type().AssignableTo(chVal.Type().Elem()) { return fmt.Errorf("参数类型%v与通道元素类型%v不匹配", argVal.Type(), chVal.Type().Elem()) } // 执行发送,这里可以加select实现非阻塞或超时逻辑 select { case chVal.Send(argVal): return nil default: return errors.New("通道已满,发送失败") } } func main() { IntChan := make(chan int, 1) StringChan := make(chan string, 1) SendToChannel(1, IntChan) SendToChannel("hello", StringChan) }
内容的提问来源于stack exchange,提问作者kfinn
相关产品推荐
相关产品推荐

