Go中接收多种struct类型作为函数参数的惯用实现方式是什么
Go语言接收多类型参数的惯用实现方案
方案1:使用泛型(推荐,Go 1.18及以上版本适用)
这是当前最符合Go惯用设计的方案,不需要给结构体额外加冗余方法,直接通过泛型的类型集合约束参数类型即可,示例代码:
import "fmt" type Thing struct { a int b int c string d string } type OtherThing struct { e int f int c string d string } // 泛型约束:仅允许传入Thing或OtherThing类型的参数 func doSomething[T Thing | OtherThing](t T) error { fmt.Println(t.d) return nil }
小提示:如果你的Go版本低于1.21,泛型直接访问共名字段可能会报错,此时可以在函数内加一层类型switch判断,或者给两个结构体添加
GetD() string方法,将泛型约束改为实现该接口即可。
方案2:标记接口(兼容Go 1.18以下版本,无泛型时使用)
给两个结构体加统一方法的方案并不是“无意义的适配”,这种叫做标记接口(Marker Interface),是Go里很常见的类型约束方式,实现也很简单:
import "fmt" type Thing struct { a int b int c string d string } type OtherThing struct { e int f int c string d string } // 定义标记接口,所有实现了isThing接口的类型都可以传入 type isThing interface { implThing() } // 给两个结构体分别实现标记方法,方法不需要任何逻辑 func (Thing) implThing() {} func (OtherThing) implThing() {} func doSomething(t isThing) error { // 用类型断言取对应字段即可 switch v := t.(type) { case Thing: fmt.Println(v.d) case OtherThing: fmt.Println(v.d) default: return fmt.Errorf("unsupported type: %T", t) } return nil }
这种方案的好处是编译期就能做类型校验,不会漏传不符合要求的类型。
方案3:空接口+类型断言(不推荐,仅临时调试用)
如果不想改结构体定义,也可以直接用interface{}作为参数类型,运行时做类型判断:
import "fmt" func doSomething(t interface{}) error { switch v := t.(type) { case Thing: fmt.Println(v.d) case OtherThing: fmt.Println(v.d) default: return fmt.Errorf("unsupported type: %T", t) } return nil }
这种方案的缺点是编译期无法校验参数类型,传错类型只能运行时报错,可维护性差,仅适合临时快速实现的场景。
方案选择建议
- 如果你用的是Go 1.18及以上版本,优先选泛型方案,代码最简洁也最符合现代Go的设计习惯
- 如果需要兼容老版本Go,优先选标记接口方案,编译期类型安全有保障
- 空接口方案仅作为临时备选,不建议在生产代码中长期使用
内容的提问来源于stack exchange,提问作者apr_1985
相关产品推荐
相关产品推荐

