英文:
Adding method to a golang struct in a different file
问题
如何在不同文件中的结构体中添加一个方法?这是我迄今为止尝试过的方法,但似乎不起作用。
// ./src
package routes
type App struct{
}
func (a *App) initializeRoutes() {
a.Subrouter.HandleFunc("/products", a.getSomething).Methods("GET")
}
// ./src/controller
package routes
func (a *App) getSomething(w http.ResponseWriter, r *http.Request){
...
}
英文:
How would one go about adding a method to a struct that is a different file?
This is what I've tried so far but it doesn't seem to be working.
// ./src
package routes
type App struct{
}
func (a *App) initializeRoutes() {
a.Subrouter.HandleFunc("/products", a.getSomething).Methods("GET")
}
// ./src/controller
package routes
func (a *App) getSomething(w http.ResponseWriter, r *http.Request){
...
}
答案1
得分: 24
他们不在同一个包中。Go包有一个名称和一个路径。它们都被命名为routes
,但它们具有不同的路径。实际的包是routes
和controller/routes
。结果是子目录是不同的包。
有关更多信息,请参阅Go博客上的“包名称”(Package Names)。
由于它们位于不同的包中,它们只能访问彼此的公共成员和导出的方法。在Go中,你不能修改其他人的包或接口。这是为了将包的所有功能集中在一个地方,避免远程操作。
你有几个选择。你可以将routes
的所有方法放入一个单独的包中。如果它们都属于同一个功能,就没有必要将其拆分为多个文件。
如果它们实际上不属于同一个功能,你可以编写一个新的结构体,将routes
嵌入其中,并在其上定义新的方法。然后,你可以访问包装结构体以获取你添加的方法,或者访问其嵌入的结构体以获取routes
的方法。参见这个答案中的示例。
但是我认为你需要考虑一下代码的组织方式。App
可能不应该由routes
包定义,它们应该是分开的。相反,Go更喜欢一种拥有关系。App
将包含一个routes.Route
的实例。
你可以像这样重新安排你的代码树:
app/
app.go
app_test.go
routes/
routes.go
routes_test.go
请注意,现在它不再全部位于src/
中,而是包含在自己的项目目录中。app.go
可能如下所示。
// src/app/app.go
package app
import(
"app/routes"
"fmt"
"net/http"
)
type App struct {
routes routes.Route
}
func (a *App) initializeRoutes() {
a.routes.AddRoute("/products", a.getSomething)
}
func (a *App) getSomething(w http.ResponseWriter, r *http.Request) {
fmt.Println("Something!")
}
注意,我们将添加路由的责任委托给a.routes
,而不是让App
自己来做。这避免了将所有功能都塞进一个庞大的包中的欲望。routes.Route
将在app/routes/routes.go
中定义。
// src/app/routes/routes.go
package routes
import "net/http"
// 用于路由处理程序的接口类型。
type RouteHandler func(w http.ResponseWriter, r *http.Request)
type Route struct {
handlers map[string]RouteHandler
}
func (r *Route) AddRoute(path string, handler RouteHandler) {
r.handlers[path] = handler
}
现在,所有的路由只需要关心处理路由。它不知道你的具体应用逻辑。
现在我们重新安排了文件结构,你可以这样做。你可以在app/controllers.go
中定义代码来组织你的代码。
// src/app/controllers.go
package app
import(
"fmt"
"net/http"
)
func (a *App) getSomething(w http.ResponseWriter, r *http.Request) {
fmt.Println("Something!")
}
app/app.go
和app/controllers.go
位于同一个包中。它们具有相同的路径和名称。因此,app/controllers.go
可以向App
添加方法。
英文:
> They are in the same package.
They are not in the same package. A Go package has both a name and a path. They're both named routes
but they have different paths. The actual packages are routes
and controller/routes
. The result is subdirectories are different packages.
See Package Names on the Go Blog for more information.
Since they're in different packages, they can only access each other's public members and exported methods. You can't monkey patch someone else's package or interface in Go. This is by design to keep all the functionality of a package in one place, no action-at-a-distance.
You have options. You could put all methods of routes
into a single package. If they all belong together, there's no need to split it up into multiple files.
If they don't really belong together, you can write a new struct with routes embedded into it and define new methods on that. Then you can access either the wrapper struct to get your added methods, or its embedded struct to get routes
' methods. See this answer for an example.
But really I think you need to think about how your code is arranged. The App
probably shouldn't be defined by the routes
package, they should be separate. Instead, Go prefers a has-a relationship. App
would contain an instance of routes.Route
.
You'd rearrange your code tree like so:
app/
app.go
app_test.go
routes/
routes.go
routes_test.go
Note that rather than having it all in src/
it's now contained in its own project directory. app.go
would look something like this.
// src/app/app.go
package app
import(
"app/routes"
"fmt"
"net/http"
)
type App struct {
routes routes.Route
}
func (a *App) initializeRoutes() {
a.routes.AddRoute("/products", a.getSomething)
}
func (a *App) getSomething(w http.ResponseWriter, r *http.Request) {
fmt.Println("Something!")
}
Notice how we're delegating responsibility to adding a route to a.routes
rather than having App
do it itself. This avoids the desire to smash all functionality into one ginormous package. routes.Route
would be defined in app/routes/routes.go
.
// src/app/routes/routes.go
package routes
import "net/http"
// A type specifying the interface for route handlers.
type RouteHandler func(w http.ResponseWriter, r *http.Request)
type Route struct {
handlers map[string]RouteHandler
}
func (r *Route) AddRoute(path string, handler RouteHandler) {
r.handlers[path] = handler
}
Now all routes has to worry about is handling routes. It doesn't know anything about your specific application logic.
> I was trying to get my http.res & http.req functions in a controllers file.
Now that we've rearranged the file structure, you can do that. You can, if you like, define app/controllers.go
to organize your code.
// src/app/controllers.go
package app
import(
"fmt"
"net/http"
)
func (a *App) getSomething(w http.ResponseWriter, r *http.Request) {
fmt.Println("Something!")
}
app/app.go
and app/controllers.go
are in the same package. They have the same path and the same name. So app/controllers.go
can add methods to App
.
答案2
得分: 2
你之所以出现错误,是因为你的文件属于不同的包。与一个结构相关的所有内容必须在同一个包中。可以在不同的文件中声明结构和其方法,但它们必须属于同一个包(位于同一个文件夹中)。
英文:
You have an error because your files belong to different packages. Everything related to one struct must be in the same package.
It is possible to declare struct and its methods in different files, but they must belong same package (be in same folder).
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论