接口名必须首字母大写且推荐用-er后缀,方法签名须字面量一致,接收者类型(值/指针)决定实现资格,嵌入接口会展开全部方法并可能引发冲突。

接口名必须是导出的,且推荐用 -er 后缀
Go 里接口名首字母小写 = 包外不可见,根本没法被其他包的结构体实现或使用。比如 type writer interface{ Write([]byte) (int, error) },哪怕你实现了所有方法,io.Copy 也不会认——它只接受 io.Writer,而后者是导出的。
更实际的坑是:团队内部自定义接口时,有人图省事写 type configLoader interface{ Load() error },结果调用方 import 包后发现类型不可见,编译直接报错 undefined: configLoader。
- 接口名必须首字母大写,如
ConfigLoader、AuthService - 命名优先用单个名词 +
er(Reader、Writer、Closer),能直观表达能力而非职责 - 避免泛泛的
Service或Manager,它们不体现行为契约,后期难以 mock 或替换
接口方法签名必须严格匹配,参数/返回值类型不能“差不多”
Go 不做类型自动转换。哪怕 []byte 和自定义的 type Bytes []byte 底层一样,也不能互相替代;int 和 int64 更是完全不同的类型。接口方法一旦定义,实现者就得原样复制签名。
典型错误:func (s *SQLStore) Get(id int) (*User, error) 声称实现了 type UserRepo interface{ Get(id int64) (*User, error) } —— 编译失败,提示 missing method Get,因为 int ≠ int64。
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 参数和返回值类型必须字面量一致,包括基础类型、别名、指针层级
- 参数名可省略或不同,但类型顺序、数量、是否指针必须完全一致
- 返回值中 error 必须显式声明,不能用
func() (err error)省略类型
接收者类型决定谁能满足接口,值 vs 指针不能混用
如果接口方法定义在 *T 上,那只有 *T 类型变量能赋值给该接口;T{} 值字面量直接报错 T does not implement X (X method has pointer receiver)。
常见于 ORM 或配置加载场景:结构体字段需要修改(比如缓存标记、连接池计数),方法自然用指针接收者,但测试时传值构造体就崩了。
- 若结构体方法需修改自身字段,必须用指针接收者,且接口使用者只能传
&t - 若方法纯读取、无副作用,用值接收者更安全(避免 nil 指针 panic),且
T和*T都能满足 - 不要在同一个接口里混用两种接收者风格——会导致部分实现无法满足
嵌入接口要小心方法冲突和隐式要求
type ReadCloser interface{ io.Reader; io.Closer } 看似只是组合,实则要求实现者同时提供 Read 和 Close 方法。如果嵌入两个都含 Close() 的接口,编译器会报 duplicate method Close。
更隐蔽的是:嵌入 io.Reader 后,你不能靠组合一个已有 Read 方法的字段来“间接实现”,Go 不会递归查找嵌套字段的方法——必须由当前类型直接实现。
- 嵌入接口 = 展开其全部方法到当前接口,不是“继承实现”
- 同名方法冲突时,必须手动解耦,比如重命名其中一个为
CloseConn或CloseFile - 空接口
interface{}不能嵌入,语法允许但无意义,因为它没方法可展开
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










