在不同的文件中为 golang 结构体添加方法。

huangapple go评论109阅读模式
英文:

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,但它们具有不同的路径。实际的包是routescontroller/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.goapp/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).

huangapple
  • 本文由 发表于 2017年7月29日 02:00:56
  • 转载请务必保留本文链接:https://go.coder-hub.com/45379722.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定