How can I overwrite anonymous struct function.
To clarify what I mean look at the following code snippet:
package base
import (
"fmt"
"net/http"
)
type Executer interface {
Execute()
}
type Controller struct { }
func (self *Controller) Execute() {
fmt.Println("Hello Controller")
}
func (self *Controller) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
self.Execute()
}
Now I am embedding the Controller struct into Test struct, also called anonymous
package base
import (
"fmt"
"net/http"
"net/http/httptest"
"testing"
)
type Test struct {
Controller
}
func (self *Test) Execute() {
fmt.Println("Hello Test")
}
func TestInheritance(t *testing.T) {
ts := httptest.NewServer(&Test{})
defer ts.Close()
http.Get(ts.URL)
}
As output I've got "Hello Controller" but expected "Hello Test". You can see code above, I reimplement the execute function, but it does not work.
Since Test has no ServeHTTP method, your test server uses Controller's, which calls Controller.Execute(). If you want it to work properly, define ServeHTTP for the Test type.
type Test struct {
Controller
}
Controller has no ServeHTTP method but *Controller has. So
type Test struct {
*Controller
}
I think it will work.
Related
How do you override a function created in another module in Golang?
Module A
In one module I have the function NewPersonApiService, the full code is laid out as below:
package openapi
import (
"context"
"errors"
"net/http"
)
// PersonApiService is a service that implements the logic for the PersonApiServicer
// This service should implement the business logic for every endpoint for the PersonApi API.
// Include any external packages or services that will be required by this service.
type PersonApiService struct {
}
// NewPersonApiService creates a default api service
func NewPersonApiService() PersonApiServicer {
return &PersonApiService{}
}
// ShowPerson - Detail
func (s *PersonApiService) ShowPerson(ctx context.Context) (ImplResponse, error) {
// TODO - update ShowPerson with the required logic for this service method.
// Add api_person_service.go to the .openapi-generator-ignore to avoid overwriting this service implementation when updating open api generation.
//TODO: Uncomment the next line to return response Response(200, Person{}) or use other options such as http.Ok ...
//return Response(200, Person{}), nil
//TODO: Uncomment the next line to return response Response(0, Error{}) or use other options such as http.Ok ...
//return Response(0, Error{}), nil
return Response(http.StatusNotImplemented, nil), errors.New("ShowPerson method not implemented")
}
Module B
In a separate module I want to override this NewPersonApiService.
I can call this function in the other module by doing the following:
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))
}
But if I try to override the function I get compilation error, unresolved type for openapi, below is what I was attempting to do:
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
}
Below is an image of the compilation error
Additional Info:
I believe Module B is properly referencing Module A.
Module A's go.mod file reads as follows:
module build/code/spec
go 1.13
require github.com/go-chi/chi/v5 v5.0.3
Module B's go.mod file reads as follows:
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
The solution was to implement the ShowPerson method in another module, you would need to create a new type that implements the PersonApiServicer interface and provides its own implementation of the ShowPerson method.
Running this in Module B worked and allowed me to change the response of the API call defined in Module A.
package main
import (
"context"
"log"
"net/http"
openapi "build/code/spec/src"
)
type MyPersonApiService struct{}
func NewMyPersonApiService() openapi.PersonApiServicer {
return &MyPersonApiService{}
}
func (s *MyPersonApiService) ShowPerson(ctx context.Context) (openapi.ImplResponse, error) {
// TODO: Add your own implementation of the ShowPerson method here.
// For example, you could retrieve a person's details and return them as follows:
person := openapi.Person{Id: 23, Name: "Vark Thins", Age: 20}
return openapi.Response(http.StatusOK, person), nil
}
func main() {
log.Printf("Server started")
PersonApiService := NewMyPersonApiService()
PersonApiController := openapi.NewPersonApiController(PersonApiService)
router := openapi.NewRouter(PersonApiController)
log.Fatal(http.ListenAndServe(":8080", router))
}
I am really new to golang and I am trying to see how encapsulation really works in go.
I have the following structure
-- package a
-a_core.go
-a.go
-models.go
-- main.go
In models.go I have structs for request and responses for an api call,
a.go has an empty struct, which is private and a public interface, which I want to expose with various methods
a_core.go just has some business logic which would be called in my interface implementation
Then, I have a main.go where I just call the public interface.
code in a.go
package a
type myFunction struct{}
type MyFunc interface {
Create(myData *MyData) (*MyData, error)
Fetch(test string)
Delete(test string)
}
//Concrete implementations that can be accessed publicly
func (a *myFunction) Create(data *MyData) (*MyData, error) {
return nil, nil
}
func (a *myFunction) Fetch(test string) {
}
func (a *myFunction) Delete(test string) {
}
In main.go, I call the interface my first create the MyData pointer with values
data := &a.MyData{
/////
}
result, err := a.MyFunc.Create(data)
I get the following error when I do this,
too few arguments in call to a.MyFunc.Create
cannot use data (variable of type *a.MyData) as a.MyFunc value in argument to a.MyFunc.Create: missing method CreatecompilerInvalidIfaceAssign
Please what am I doing wrong?
Here is an example
Note that names in uppercase are public, in lowercase private (see https://tour.golang.org/basics/3 )
./go-example/main.go
package main
import "go-example/animal"
func main() {
var a animal.Animal
a = animal.Lion{Age: 10}
a.Breathe()
a.Walk()
}
./go-example/animal/animal.go
package animal
import "fmt"
type Animal interface {
Breathe()
Walk()
}
type Lion struct {
Age int
}
func (l Lion) Breathe() {
fmt.Println("Lion breathes")
}
func (l Lion) Walk() {
fmt.Println("Lion walk")
}
I have an interface in the service package
databaseService.go
package service
import "gitlab.com/xert/customerservice/internal/database/models"
type CustomerdetailsServiceInterface interface {
// Remove deletes a user by user name from database.
Add()
}
Then I have another service file customerDetailsService.go,where i am implementing the interface methods
type CustomerdetailService struct {
}
func Add(ud *CustomerdetailService) {
fmt.Println("hello")
}
Now when I am trying to use it my main.go
import (
"gitlab.com/xert/customerservice/internal/database/service"
)
func main() {
service.CustomerdetailsServiceInterface.Add() // this is complaining too few arguments
}
How to call the method like this, implement methods in other file?
You have not implemented CustomerdetailsServiceInterface in the first place. Following is the way you can implement it.
type CustomerdetailService struct {}
func (ud *CustomerdetailService) Add() {
fmt.Println("hello")
}
See the following code, hope it will help you understanding interface in go.
package main
import (
"fmt"
)
type CustomerdetailsServiceInterface interface {
Add()
}
type CustomerdetailService struct{}
func (ud *CustomerdetailService) Add() {
fmt.Println("hello")
}
type AnotherCustomerdetailService struct{}
func (ud *AnotherCustomerdetailService) Add() {
fmt.Println("Modified Addition")
}
func main() {
var x CustomerdetailsServiceInterface
x = &CustomerdetailService{}
x.Add()
x = &AnotherCustomerdetailService{}
x.Add()
}
You can not call a method directly on interface but you will need a variable with a type which implements the interface. In the above case it's CustomerdetailService which implements CustomerdetailsServiceInterface.
Is there a way to add a tag or annotate some methods so that whenever an event arises all the methods with this tag or annotation get invoked?
How to achieve this in Go?
As others have said, no there are no annotations or tags on functions in Go.
However, it is more than possible to use a map (or slice) and a register function to keep records of other funcs (or interfaces). You just need to manually call that register func (usually in init() of that package).
For example,
package events
var eventFuncs = make(map[string]func())
func Register(event string, f func()) {
eventFuncs[event] = append(eventFuncs[event],f)
}
func Get(event string) []func() {
return eventFuncs[event]
}
And using the package to register:
package xy
import (
"fmt"
"some.url/events"
)
func Call() {
fmt.Println("Ha!")
}
func init() {
events.Register("x",Call)
}
And then call the funcs elsewhere:
package main
import (
"some.url/events"
)
func main() {
for _,f := range pkg.GetEvent("x") { f() }
}
Problem at reflection, with MethodByName
Code:
package main
import (
"reflect"
"fmt"
)
type test struct {}
var serviceType = map[string]reflect.Value{
"test": reflect.ValueOf(test{}),
}
func (t *test) prnt() {
fmt.Println("test ok")
}
func callFunc(strct string, fName string) {
s := serviceType[strct].MethodByName(fName)
if !s.IsValid(){
fmt.Println("not correct")
return
}
s.Call(make([]reflect.Value,0))
}
func main() {
callFunc("test", "prnt")
}
Output:
not correct
Playground:
https://play.golang.org/p/ZLEQBGYoUOB
Could you help, what I'm doing wrong ?
Two things needs to be corrected.
MethodByName() returns only Exported methods. So you have to rename prnt tp Prnt
Needs to pass a pointer of struct test to reflect.ValueOf() method.
Here is the modified working code https://play.golang.org/p/4MK2kqOz6e2