如何在Golang中覆写其他模块的函数?
Go模块间覆写服务方法编译错误问题
问题描述
在Module A的openapi包中定义了PersonApiService结构体、NewPersonApiService函数及未实现的ShowPerson方法。Module B可正常调用该模块的服务创建与路由逻辑,但尝试覆写PersonApiService的ShowPerson方法时触发编译错误,提示未解析的openapi类型。
相关代码
Module A代码
package openapi import ( "context" "errors" "net/http" ) // PersonApiService 实现PersonApiServicer逻辑的服务结构体 type PersonApiService struct { } // NewPersonApiService 创建默认的api服务实例 func NewPersonApiService() PersonApiServicer { return &PersonApiService{} } // ShowPerson - 详情接口 func (s *PersonApiService) ShowPerson(ctx context.Context) (ImplResponse, error) { return Response(http.StatusNotImplemented, nil), errors.New("ShowPerson method not implemented") }
Module B正常调用代码
package main import ( "log" "net/http" openapi "build/code/spec/src" ) func main() { log.Printf("Server started") personApiService := openapi.NewPersonApiService() personApiController := openapi.NewPersonApiController(personApiService) router := openapi.NewRouter(personApiController) log.Fatal(http.ListenAndServe(":8080", router)) }
Module B尝试覆写的代码(报错版本)
package main import ( "context" "log" "net/http" openapi "build/code/spec/src" ) func main() { log.Printf("Server started") personApiService := openapi.NewPersonApiService() personApiController := openapi.NewPersonApiController(personApiService) router := openapi.NewRouter(personApiController) log.Fatal(http.ListenAndServe(":8080", router)) } func (s openapi.PersonApiService) ShowPerson(ctx context.Context) (openapi.ImplResponse, error) { return openapi.Response(200, openapi.Person{}), nil }
模块配置
Module A的go.mod
module build/code/spec go 1.13 require github.com/go-chi/chi/v5 v5.0.3
Module B的go.mod
module bakkt.com/boilerplate go 1.19 replace build/code/spec => ./../build/generated/ require build/code/spec v0.0.0-00010101000000-000000000000 require github.com/go-chi/chi/v5 v5.0.3 // indirect
问题原因
- Go语言的方法属于定义它的包,无法在其他包中直接修改或覆写已有结构体的方法,你在Module B中尝试给
openapi.PersonApiService添加方法的做法本身不符合Go的包机制。 - 原
ShowPerson方法使用的是指针接收器(*PersonApiService),而你尝试添加的是值接收器的方法,即使语法允许,也不会覆盖原方法,反而会新增一个不同的方法。 - Module A返回的是
PersonApiServicer接口类型,正确的扩展方式是实现该接口,而非修改原有结构体。
解决方案
通过自定义结构体实现PersonApiServicer接口来替代原有服务,或者嵌入原有结构体复用其他方法,示例代码如下:
package main import ( "context" "log" "net/http" openapi "build/code/spec/src" ) // 自定义服务结构体,嵌入原有服务以复用其他未修改的方法 type CustomPersonApiService struct { *openapi.PersonApiService } // 实现自定义的ShowPerson方法 func (s *CustomPersonApiService) ShowPerson(ctx context.Context) (openapi.ImplResponse, error) { return openapi.Response(200, openapi.Person{}), nil } func main() { log.Printf("Server started") // 创建自定义服务实例,将接口类型断言为具体结构体指针 personApiService := &CustomPersonApiService{openapi.NewPersonApiService().(*openapi.PersonApiService)} personApiController := openapi.NewPersonApiController(personApiService) router := openapi.NewRouter(personApiController) log.Fatal(http.ListenAndServe(":8080", router)) }
说明
- 自定义结构体
CustomPersonApiService嵌入*openapi.PersonApiService,自动继承原有结构体的所有方法,仅重写需要修改的ShowPerson方法即可。 - 由于
NewPersonApiService返回的是PersonApiServicer接口,需要通过类型断言转换为具体的*openapi.PersonApiService才能完成嵌入。 - 自定义结构体实现了
PersonApiServicer接口,可直接传递给NewPersonApiController使用,完全兼容原有路由逻辑。
内容的提问来源于stack exchange,提问作者Mabel Oza
相关产品推荐
相关产品推荐

