英文:
Defining an interface method with interface return type
问题
TLDR 这是一个演示问题的游乐场:https://play.golang.org/p/myQtUVg1iq
我正在创建一个 REST API,并且有许多类型的资源可以通过 GET 请求获取:
GET http://localhost/api/users
GET http://localhost/api/groups
我有一个模型包,用于抽象不同资源的实现方式:
func(m *UserManager) Get() []Users {
// 内部逻辑,假设返回正确的结果
}
func(m *GroupManager) Get() []Groups {
// 内部逻辑,假设返回正确的结果
}
一个路由文件设置所有的路由和处理程序:
users := models.UserManager{}
groups := models.GroupManager{}
func GetUsersHandler (w http.ResponseWriter, r *http.Request) {
users := users.Get()
// 实现细节,将结果以 JSON 格式写入 w
}
func GetGroupsHandler (w http.ResponseWriter, r *http.Request) {
groups := groups.Get()
// 实现细节,将结果以 JSON 格式写入 w
}
func registerRoutes(r *mux.Router) {
r.handleFunc("/api/users", GetUsersHandler).Method("GET")
r.handleFunc("/api/groups", GetGroupsHandler).Method("GET")
}
我试图通过创建一个接口,然后只需要一个 GetHandler 来使其更通用。类似这样:
type Getter interface {
Get() []interface{}
}
func GetHandler(g Getter) {
return func(w http.ResponseWriter, r *http.Request) {
results := g.Get()
// 实现细节,将结果以 JSON 格式写入 w
}
}
func registerRoutes(r *mux.Router) {
r.handleFunc("/api/users", GetHandler(&users)).Method("GET")
r.handleFunc("/api/groups", GetHandler(&groups)).Method("GET")
}
这非常接近工作,唯一的问题是模型的返回类型是特定的对象类型,但接口只使用了接口返回类型。有没有办法在不使模型返回 []interface{}
的情况下解决这个问题?
https://play.golang.org/p/myQtUVg1iq
英文:
TLDR Here is a playground that demonstrates the issue if you try to run it: https://play.golang.org/p/myQtUVg1iq
I am making a REST API and have many types of resources that can be retrieved via a GET request
GET http://localhost/api/users
GET http://localhost/api/groups
I have a models package which abstracts how the different resources are implemented:
func(m *UserManager) Get() []Users {
// Internal logic, assume returns correct results
}
func(m *GroupManager) Get() []Groups {
// Internal logic, assume returns correct results
}
A routes file setups all the routes and handlers:
users := models.UserManager{}
groups := models.GroupManager{}
func GetUsersHandler (w http.ResponseWriter, r *http.Request) {
users := users.Get()
// Implementation details, writing to w as JSON
}
func GetGroupsHandler (w http.ResponseWriter, r *http.Request) {
groups := groups.Get()
// Implementation details, writing to w as JSON
}
func registerRoutes(r *mux.Router) {
r.handleFunc("/api/users", GetUsersHandler).Method("GET")
r.handleFunc("/api/groups", GetGroupsHandler).Method("GET")
}
I am trying to make this more generic by creating an interface and then only needing a single GetHandler. Something like this:
type Getter interface {
Get() []interface{}
}
func GetHandler(g Getter) {
return func(w http.ResponseWriter, r *http.Request) {
results := g.Get()
// Implementation details, writing to w as JSON
}
}
func registerRoutes(r *mux.Router) {
r.handleFunc("/api/users", GetHandler(&users)).Method("GET")
r.handleFunc("/api/groups", GetHandler(&groups)).Method("GET")
}
This is really close to working, the only problem is the return type from the models is a specific object type, but the interface just uses the interface return type. Is there any way to solve this without making the models return []interface{}
?
答案1
得分: 0
尝试不要像处理其他面向对象编程语言那样处理这个问题。在Go语言中,你不能拥有协变容器,所以你要么使用空的interface{}
,要么以不同的方式组织你的程序。
如果你的Get
方法是不同的,并且你想在一个接口中对类型进行分组,可以使用另一种方法(有时我们甚至为接口添加空操作方法),或者将users
或groups
作为interface{}
传入。你仍然需要在调用链中的某个地方进行类型切换或断言,一旦你知道了类型,就可以相应地处理它。
没有更多的代码很难确定,但在这种情况下,最简单的方法可能就是让每种类型本身成为http.Handler
,然后它可以相应地进行分发。
英文:
Try not to approach the problem like you would other OOP languages. You can't have covariant containers in Go, so you either have to use an empty interface{}
, or you have to structure your program differently.
If your Get
methods are different and you want to group types in an interface, use another method (sometimes we even have noop methods just for interfaces), or just pass in users
or groups
as an interface{}
. You'll need to do a type switch or assertion at some point in the call chain anyway, and once you know what type it is you can handle it accordingly.
It's hard to tell without more code, but in this case, the easiest path may just be to have each type be an http.Handler
itself, and it can dispatch accordingly.
答案2
得分: 0
我最终完全避免了这个问题,而是使用了Go 1.4中的新功能go generate
来创建每个资源所需的代码,而不是试图减少我使用的代码量。
英文:
I ended up avoiding this problem entirely and instead of trying to reduce the amount of code I am using the new go generate
feature in Go 1.4 to create the code that is necessary for each resource.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论