mcpField
G
go-interfaces

go-interfaces

github.com/cxuu开发1861.3k 次安装19 周前更新
代码仓库

关于 go-interfaces

面向 Go 开发者的接口设计技能,涵盖类型断言、嵌入和接收者选择,并提供检查接口合规性的脚本与参考资料。

主要功能

  1. 01由使用方定义接口
  2. 02具体类型与接口返回建议
  3. 03安全类型断言与类型分支
  4. 04嵌入与接收者类型建议
  5. 05编译时接口检查

适用场景

  1. 01设计包 API 和构造函数
  2. 02检查类型是否满足接口
  3. 03审查公开结构体中的嵌入

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/cxuu/golang-skills --skill go-interfaces

安装后在 Claude Code 中输入/go-interfaces确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
EMBEDDING.md
RECEIVER-TYPE.md
scripts/
check-interface-compliance.go
check-interface-compliance.sh

详细介绍

Go 接口与组合

资源路由

  • scripts/check-interface-compliance.sh - 作为启发式检查运行,找出可能需要编译时断言的导出接口。
  • scripts/check-interface-compliance.go - 由 check-interface-compliance.sh 调用的实现辅助程序;更改方法集分析时修改此文件。
  • references/EMBEDDING.md - 在公共 API 中嵌入接口或结构体时阅读。
  • references/RECEIVER-TYPE.md - 指针/值接收者影响接口满足条件时阅读。

接受接口,返回具体类型

接口应属于使用值的包,而不是实现接口的包。构造函数应返回具体类型(通常是指针或结构体),这样添加新方法时无需重构。

// Good: consumer defines the interface it needs
package consumer

type Thinger interface { Thing() bool }

func Foo(t Thinger) string { ... }
// Good: producer returns concrete type
package producer

type Thinger struct{ ... }
func (t Thinger) Thing() bool { ... }
func NewThinger() Thinger { return Thinger{ ... } }
// Bad: producer defines and returns its own interface
package producer

type Thinger interface { Thing() bool }
type defaultThinger struct{ ... }
func NewThinger() Thinger { return defaultThinger{ ... } }

不要在使用接口之前定义接口。 如果没有真实的使用示例,就很难判断接口是否真的有必要。


通用性:隐藏实现,公开接口

如果某个类型的存在只是为了实现接口,且除该接口外没有其他导出方法,那么构造函数应返回接口,以隐藏实现:

func NewHash() hash.Hash32 {
    return &myHash{}  // unexported type
}

优点:实现可以更改而不影响调用方;替换算法只需更改构造函数调用。


类型断言:逗号 ok 惯用法

如果不进行检查,断言失败会导致运行时 panic。务必使用逗号 ok 惯用法进行安全测试:

str, ok := value.(string)
if ok {
    fmt.Printf("string value is: %q\n", str)
}

检查某个值是否实现了接口:

if _, ok := val.(json.Marshaler); ok {
    fmt.Printf("value %v implements json.Marshaler\n", val)
}

类型 switch

惯用做法是重复使用变量名(t := t.(type))——在每个 case 分支中,该变量都具有正确的类型。如果一个 case 列出多种类型(case int, int64:),该变量的类型就是接口类型。


嵌入

避免在公共结构体中嵌入类型——内部类型的完整方法集会成为公共 API 的一部分。请改用非导出字段。


接口满足性检查

使用空白标识符赋值,在编译时验证某个类型是否实现了接口:

var _ json.Marshaler = (*RawMessage)(nil)

如果 *RawMessage 未实现 json.Marshaler,这会导致编译错误。

在以下情况下使用此模式:

  • 没有静态转换可自动验证接口
  • 类型必须满足某个接口才能确保行为正确(例如,自定义 JSON 编码)
  • 接口发生更改时应导致编译失败,而不是悄然降级

不要为每个接口都添加此类检查——只在没有其他静态转换可以捕获错误时添加。

验证:定义接口或实现后,运行 bash scripts/check-interface-compliance.sh,以确认所有具体类型都有编译时 var _ I = (*T)(nil) 检查。


接收者类型

如果不确定,请使用指针接收者。不要在同一个类型上混用接收者类型——如果有任何方法需要指针,就让所有方法都使用指针。仅对小型不可变类型(Point、time.Time)或基本类型使用值接收者。


快速参考

概念模式说明
接口由使用方定义在使用处定义接口不要在实现接口的包中定义
安全的类型断言v, ok := x.(Type)返回零值 + false
类型 switchswitch v := x.(type)变量在每个 case 中具有正确的类型
接口嵌入type RW interface { Reader; Writer }方法的并集
结构体嵌入type S struct { *T }提升 T 的方法
接口检查var _ I = (*T)(nil)编译时验证
通用性构造函数返回接口隐藏实现

相关技能

  • 接口命名:命名接口(-er 后缀约定)或选择接收者名称时,请参阅 go-naming
  • 错误类型:实现 error 接口、自定义错误类型或使用 errors.As 匹配时,请参阅 go-error-handling
  • 泛型与接口:判断是否需要泛型,或接口是否已足够时,请参阅 go-generics
  • 函数选项:使用基于接口的 Option 模式来实现灵活的构造函数时,请参阅 go-functional-options
  • 防御性边界:当接口断言只是更广泛的 API 边界加固工作的一部分时,请参阅 go-defensive

评论

支持 Markdown