Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding method to a golang struct in a different file

Tags:

methods

struct

go

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){

...

}
like image 822
Joseph Palacio Avatar asked Nov 30 '22 15:11

Joseph Palacio


1 Answers

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.

like image 64
Schwern Avatar answered Dec 04 '22 14:12

Schwern