I currently have the following code
func (r *Router) Get(path string, controller interface{}) {
...
t := reflect.TypeOf(controller)
...
}
That is called doing the following
Route.Get("/", controllers.Test.IsWorking)
The second argument is basically this
type Test struct {
*Controller
Name string
}
func (t Test) IsWorking() {
}
type Controller struct {
Method string
Request *http.Request
Response http.ResponseWriter
Data map[interface{}]interface{}
}
I want to get the struct the function refers to. create a new struct of that type and call the function so for example
controllers.Test.IsWorking
Create a Test struct and call IsWorking()
To make a new pointer to a newly allocated struct of the type in the interface, all you need is
newController := reflect.New(reflect.TypeOf(controller)).Interface()
Or to set a value on the new instance first:
newController := reflect.New(reflect.TypeOf(controller))
newController.Elem().FieldbyName("Method").Set(reflect.ValueOf("GET"))
If you want to create a pointer to a struct and call the IsWorking method, it looks like
t := reflect.New(reflect.TypeOf(Test{}))
t.MethodByName("IsWorking").Call(nil)
Related
I need to pass a struct as a reference to a function; however, I cannot use pointer (*) syntax in my function parameters:
func abc(client cleintpassedasrefernce) {
// make changes in client so that it will be updated in the client actual memory location
}
type clienttobepassasref struct {
data int
name string
}
// calling abc function
object = clienttobepassasref{}
abc(object)
Maybe I can create another struct like type object passed struct
{
object *clienttobepassasref
}
and pass this object and access it later in the function?
You need to change both the function signature, and the method by which you're calling the function. Also you're defining a struct type called clienttobepassasref but your function is accepting a struct type of cleintpassedasrefernce which is not defined in your example. I replaced these with a struct type in my example called MyObject.
go playground
package main
import (
"fmt"
)
type MyObject struct {
data int
name string
}
// accept a pointer to the object here using the '*' character
func abc(obj *MyObject) {
// make changes in client so that it will be updated in the client actual memory location
obj.name = "foo"
}
func main() {
// calling abc function
object := MyObject{}
abc(&object)
// Pass it by reference here with the '&' character
fmt.Println(object.name)
}
If you need to update, change struct's properties, then create a function (method) with receiver of that struct reference and update struct's properties in that function (method).
package main
import "fmt"
type MyObject struct {
data int
name string
}
func (obj *MyObject)abc() {
// make changes in client so that it will be updated in the client actual memory location
obj.name = `some name`
obj.data = 10
}
func main() {
// calling abc function
object := &MyObject{}
object.abc()
fmt.Printf("object = %+v", *object)
//object = {data:10 name:some name}
}
run the code here
reference to get some more knowledge
tour.golang.org
go-method-receiver-pointer-vs-value
I have a struct, say:
type sample struct{
data []float64
}
Now, I declare a method:
func (s sample) Get() *[]float64{
return &s.data
}
I am trying to append to this slice via the pointer I got via Get()
func main(){
example := sample{[]float64{1,2,3}}
//Here I will append:
pointerToArray := example.Get()
*pointerToArray = append(*pointerToArray, 4)
fmt.Println(example.Get()) // still shows only &{1,2,3}
}
I have a general idea of why this is happening: The function Get is returning the address of its local scope, and I have fixed it by change the struct itself to
type sample struct{
data *[]float64
}
for which the code returns the expected &{1,2,3,4}
Now, for my question:
Is there anyway to get the real pointer to the field in the struct through a getter method without using a pointer field directly in the struct?
The problem is that you've defined the Get method with a struct receiver, rather than on a pointer. That means when you return &s.data you get the address of the field of receiver, rather than from the original struct. You can fix this simply by using a pointer receiver:
func (s *sample) Get() *[]float64{
return &s.data
}
Here's a complete runnable example (https://play.golang.org/p/AIj8QOYfx85)
package main
import "fmt"
type sample struct {
data []float64
}
func (s *sample) Get() *[]float64 {
return &s.data
}
func main() {
example := sample{[]float64{1, 2, 3}}
p := example.Get()
*p = append(*p, 4)
fmt.Println(example.Get())
}
I have code in Go, which includes many execution methods.
Each method receives it own struct of parameters.
I want a dispatcher to call each method with its related struct.
The dispatcher receives the name of the execution method, and a JSON of the parameters struct.
Then, it uses reflection to build the struct, and calls the method.
The problem is I get compilation error unless I create the execution methods using empty interface.
In the example below I have 2 execution methods: api1 is compiling, but is using the empty interface and explicit casting. api2 is what I want to do, but it is failing with compile error:
cannot use api2 (type func(Api2Parameters)) as type Api in assignment
How can I make api2 usage compile?
import (
"encoding/json"
"log"
"reflect"
)
type Api func(arguments interface{})
type ApiDetails struct {
Executor *Api
ParametersType reflect.Type
}
var Apis map[string]*ApiDetails
func RunApi(apiName string, data string) {
api := Apis[apiName]
parameters := reflect.New(api.ParametersType).Interface().(interface{})
_ = json.Unmarshal([]byte(data), parameters)
(*api.Executor)(parameters)
}
type Api1Parameters struct {
Count1 int
Id1 string
}
func api1(arguments interface{}) {
parameters, _ := arguments.(*Api1Parameters)
log.Printf("api1 parameters(%+v)", parameters)
}
type Api2Parameters struct {
Count2 int
Id2 string
}
func api2(arguments Api2Parameters) {
log.Printf("api2 parameters(%+v)", arguments)
}
func Test() {
// this assignment works fine
var api_1 Api = api1
Apis["api1"] = &ApiDetails{
Executor: &api_1,
ParametersType: reflect.TypeOf(Api1Parameters{}),
}
// this assignment produce compile error
var api_2 Api = api2
Apis["api2"] = &ApiDetails{
Executor: &api_2,
ParametersType: reflect.TypeOf(Api2Parameters{}),
}
RunApi("api1", `{"Count1":19, "Id1":"a"}`)
RunApi("api2", `{"Count2":34, "Id2":"b"}`)
}
Create a value using the argument type, unmarshal to that value and invoke the function:
var Apis = map[string]interface{}{
"api1": api1,
"api2": api2,
}
func RunApi(apiName string, data string) {
fv := reflect.ValueOf(Apis[apiName])
ft := fv.Type()
pin := reflect.New(ft.In(0))
_ = json.Unmarshal([]byte(data), pin.Interface())
fv.Call([]reflect.Value{pin.Elem()})
}
Run it on the playground.
If you want to keep this type-safe, you can push the JSON-to-args conversion a little deeper:
type Api func(string)
type ApiDetails struct {
// Don't use *Api, that's a function pointer-pointer
Executor Api
}
Then, use a closure to do the JSON translation:
Apis["api1"] = &ApiDetails{
Executor: func(data string) {
var args ArgsForAPI1
json.Unmarshal([]byte(string),&args)
api1Implem(args)
}
}
With this, you can do:
APIs["api1"].Executor( `{"Count1":19, "Id1":"a"}`)
You can change the RunApi to do something like this.
A second option is to do this using reflection:
type ApiDetails struct {
// Executor can accept any function signature
// Assume a function with a single parameter
Executor interface{}
ParametersType reflect.Type
}
Then, the RunApi function can use reflection to construct a struct and call Executor:
parameters := reflect.New(api.ParametersType)
_ = json.Unmarshal([]byte(data), parameters.Interface{})
reflect.ValueOf(api.Executor).Call([]reflect.Value{parameters})
This should work, but you'll only get runtime errors if you mess up.
For example, I want to write a method like this:
func parseData(rawData []json.RawMessage) []interface{} {
var migrations []interface{}
for _, migration := range rawData {
// this is an custom struct
command := UserCommand{}
json.Unmarshal(migration, &command)
migrations = append(migrations, command)
}
return migrations
}
The problem of this code is: If I don't want to parse UserCommand but any other such as ProductCommand, I must write the same code, only different at line: command := UserCommand{}. So my question is: how can I generic this code.
I have tried this solution but it doesn't work:
func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
var migrations []interface{}
for _, migration := range rawData {
command := class
json.Unmarshal(migration, &command)
migrations = append(migrations, command)
}
return migrations
}
// then I call this method
parseData(data, UserCommand{})
But it doesn't work. It return array of map[string]interface{} How can I fix this.
Edit:
Here is some my defined struct
type UserCommand struct {
User string
Info string
}
type ProductCommand struct {
Name string
Quanlity int
}
// I want to be able to call this method
parseData(data, UserCommand{})
It is possible to support this style of "generic" signature by using Go's reflect package.
package main
import (
"encoding/json"
"fmt"
"reflect"
)
type UserCommand struct {
User string
Info string
}
type ProductCommand struct {
Name string
Quantity int
}
func parseData(rawData []json.RawMessage, class interface{}) []interface{} {
var parsed []interface{}
for _, elem := range rawData {
// Create a pointer to a new zero value of the same type as `class`.
command := reflect.New(reflect.TypeOf(class))
// Pass a pointer to the new value to `json.Unmarshal`.
json.Unmarshal(elem, command.Interface())
// Insert the pointed-to new value into the output slice.
parsed = append(parsed, command.Elem().Interface())
}
return parsed
}
func main() {
data := []json.RawMessage{
json.RawMessage(`{"User":"u1","Info":"i1"}`),
json.RawMessage(`{"User":"u2","Info":"i2"}`),
}
parsed := parseData(data, UserCommand{})
fmt.Printf("%#v\n", parsed)
data = []json.RawMessage{
json.RawMessage(`{"Name":"n1","Quantity":1}`),
json.RawMessage(`{"Name":"n2","Quantity":2}`),
}
parsed = parseData(data, ProductCommand{})
fmt.Printf("%#v\n", parsed)
}
The output shows that the first parseData call has parsed two UserCommand structs and the second call has parsed two ProductCommand structs.
[]interface {}{main.UserCommand{User:"u1", Info:"i1"}, main.UserCommand{User:"u2", Info:"i2"}}
[]interface {}{main.ProductCommand{Name:"n1", Quantity:1}, main.ProductCommand{Name:"n2", Quantity:2}}
I have the following code:
package vault
type Client interface {
GetHealth() error
}
func (c DefaultClient) GetHealth () error {
resp := &VaultHealthResponse{}
err := c.get(resp, "/v1/sys/health")
if err != nil {
return err
}
return nil;
}
Now, I want to use this function as part of this struct:
type DependencyHealthFunction func() error
type Dependency struct {
Name string `json:"name"`
Required bool `json:"required"`
Healthy bool `json:"healthy"`
Error error `json:"error,omitempty"`
HealthFunction DependencyHealthFunction
}
Basically, set the value of HealthFunction to GetHealth. Now, when I do the following:
func (config *Config) GetDependencies() *health.Dependency {
vaultDependency := health.Dependency{
Name: "Vault",
Required: true,
Healthy: true,
HealthFunction: vault.Client.GetHealth,
}
temp1 := &vaultDependency
return temp1;
}
This gives me an error and it says cannot use vault.Client.GetHealth (type func(vault.Client) error) as type health.DependencyHealthFunction in field value. How can I do this?
Edit: How DependencyHealthFunction is used?
As its part of Dependency struct, it's simply used as following: d.HealthFunction() where d is a variable of type *Dependency.
This is abstract:
HealthFunction: vault.Client.GetHealth,
If we were to call HealthFunction(), what code do you expect to run? vault.Client.GetHealth is just a promise that such a function exists; it isn't a function itself. Client is just an interface.
You need to create something that conforms to Client and pass its GetHealth. For example, if you had a existing DefaultClient such as:
defaultClient := DefaultClient{}
Then you could pass its function:
HealthFunction: defaultClient.GetHealth,
Now when you later call HealthFunction() it will be the same as calling defaultClient.GetHealth().
https://play.golang.org/p/9Lw7uc0GaE
I believe the issue is related to understanding how interfaces are treated in Go.
An interface simply defines a method or set of methods that a particular type must satisfy to be considered as "implementing" the interface.
For example:
import "fmt"
type Greeter interface {
SayHello() string
}
type EnglishGreeter struct{}
// Satisfaction of SayHello method
func (eg *EnglishGreeter) SayHello() string {
return "Hello"
}
type SpanishGreeter struct{}
func (sg *SpanishGreeter) SayHello() string {
return "Ola"
}
func GreetPerson(g Greeter) {
fmt.Println(g.SayHello())
}
func main() {
eg := &EnglishGreeter{}
sg := &SpanishGreeter{}
// greet person in english
GreetPerson(eg)
// greet person in spanish
GreetPerson(sg)
}
You can add this behavior into a custom struct by simply having a Greeter field inside the struct. ie
type FrontEntrance struct {
EntranceGreeter Greeter
}
fe := &FrontEntrance { EntranceGreeter: &EnglishGreeter{} }
// then call the SayHello() method like this
fe.EntranceGreeter.SayHello()
Interfaces in golang are useful for composing common expected behavior for types based on the methods that they satisfy.
Hope this helps.