go中适配器用于解决接口不兼容问题,核心是方法签名匹配;常见错误源于参数类型、接收者指针、error类型等不一致;struct wrapper或函数类型(如handlerfunc)是两种主要适配方式,需注意空指针、context传递和error包装。

Go 里写适配器不是为了“套设计模式”,而是为了解决一个具体问题:你手上有个类型(比如 *zap.Logger 或 http.HandlerFunc),但调用方只认另一个接口(比如 fmt.Printer 或 http.Handler),而你又不能改对方代码——这时候才需要适配。
为什么直接赋值会报错:cannot use xxx as type YYY
这是最常卡住人的地方。错误本质是方法签名不匹配,不是“少个适配器类”。Go 接口是隐式实现的,只要缺一个参数类型、多一个 error、返回值顺序不对、甚至接收者是 *T 但你传了 T,就会报这个错。
-
error和*errors.Error不兼容;[]byte和io.Reader不自动转换 - 目标接口方法用指针接收者(
func (t *MyType) Do()),你就必须传*MyType,不能传MyType - 函数字面量直接传给接口变量时,得先确认该接口是否支持函数类型转换(如
http.HandlerFunc)
struct wrapper 适配:什么时候必须定义新 struct
当两个接口方法名/参数/返回值不完全一致,且你无法修改任一端定义时,就得靠包装结构体显式实现目标接口。
Go语言(Golang)1.26.0版本提供 Go 官方 Windows amd64 MSI 安装包下载入口,版本号 1.26.0,可用于旧项目维护、兼容性测试和指定版本开发环境配置。
- 别用
type MyAdapter = ExistingType—— 这只是别名,不继承方法 - 正确姿势是
type MyAdapter struct { impl *RealService },然后在该 struct 上逐个实现目标接口方法 - 如果原类型已实现部分方法,可匿名嵌入(
struct { *RealService })省转发代码,但要注意空指针 panic 风险,构造时要校验impl != nil - 涉及
context.Context时别丢:目标接口没 context?要么用context.Background()显式降级,要么加 wrapper 参数透传(如func (a *Adapter) WithContext(ctx context.Context) *Adapter)
函数适配器:比 struct 更轻量的选择
目标接口只有一个方法时,函数类型转接口是最干净的方案,标准库大量使用(如 http.HandlerFunc)。
- 定义:
type HandlerFunc func(http.ResponseWriter, *http.Request),再实现ServeHTTP方法调用自身 - 使用:
http.Handle("/path", HandlerFunc(myHandler)),无需额外 struct - 注意:函数类型不能嵌入 struct,也不能直接添加字段;若需携带状态(如配置、client),还是得回到 struct wrapper
- 多个函数适配同一接口?用闭包封装依赖,避免全局变量或重复初始化
容易被忽略的三个坑:空指针、context、error 包装
适配器不是透明管道,这三处出错不会立刻报编译错误,但上线后会 panic 或行为异常。
- 嵌入字段为
nil时调用方法直接 panic —— 构造函数里加if src == nil { panic("nil adaptee") } - 原接口带
context.Context,目标接口没暴露,别在适配器里硬塞context.TODO(),要明确语义:是降级(Background()),还是拒绝(返回 error) - 错误处理别裸传:原接口返回
err,目标接口也返回err,但类型可能不同(如net.OpErrorvs 自定义 error),需做包装或类型断言,否则下游errors.Is()失效
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










