Go Relflect Declare type struct - go

I wish I could recover my type of structure and declare a variable of that type .
I tried with Reflect but I can not find the way .
package main
import (
"fmt"
"reflect"
)
type M struct {
Name string
}
func main() {
type S struct {
*M
}
s := S{}
st := reflect.TypeOf(s)
Field, _ := st.FieldByName("M")
Type := Field.Type
test := Type.Elem()
fmt.Print(test)
}

Use reflect.New with your type, here's an example of setting Name on a new instance of M struct using reflection:
package main
import (
"fmt"
"reflect"
)
type M struct {
Name string
}
func main() {
type S struct {
*M
}
s := S{}
mStruct, _ := reflect.TypeOf(s).FieldByName("M")
mInstance := reflect.New(mStruct.Type.Elem())
nameField := mInstance.Elem().FieldByName("Name")
nameField.SetString("test")
fmt.Print(mInstance)
}

Related

Property name of a structure to string

I would like to know if it is possible to get the name of a property from a structure and convert it to string.
For example in the following code:
package main
import "fmt"
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
//pass any attribute of any structure
fmt.Println(castProperty(StructB.RefStructA.ValueAA))
//print the name passed but in string. Do not print the value
//expected output: "StructB.RefStructA.ValueAA"
}
func castProperty(value interface{}) string {
//some code
}
Is it possible to write a function that allows obtaining the name of the property of a structure and converted to a string? property value is not required.
That's called Reflection. I let you read the page, it lets you do what you want.
First, read the The first law of reflection: https://go.dev/blog/laws-of-reflection
package main
import (
"fmt"
"reflect"
)
func main() {
var x float64 = 3.4
fmt.Println("type:", reflect.TypeOf(x))
}
https://play.golang.org/p/OuGgD1TlSMO
I am not sure exactly how do you want to give input to your function but here is an example that may help you
package main
import (
"log"
"reflect"
)
func main() {
getPropertyName(B{})
}
type A struct {
field1 string
}
type B struct {
field A
}
func getPropertyName(b interface{}) {
parentType := reflect.TypeOf(b)
val := reflect.ValueOf(b)
for i := 0; i< val.Type().NumField(); i++ {
t := val.Type().Field(i)
ty := val.Type().Field(i).Type.Name()
log.Println(parentType.Name()+"."+ t.Name+"."+ty)
}
}
you could do something like this :
package main
import (
"fmt"
)
type StructA struct {
ValueAA string
ValueAB string
}
type StructB struct {
ValueBA string
ValueBB string
RefStructA StructA
}
func main() {
x := &StructB{RefStructA: StructA{ValueAA: "something"}}
fmt.Printf("%+v", x)
}
out :
&{ValueBA: ValueBB: RefStructA:{ValueAA:something ValueAB:}}

Check if a method type matches a function type

Given the following example, how to check if a method matches a function signature?
package main
import (
"fmt"
"context"
"reflect"
)
// signature to check
type Fn func(context.Context)
type testStruct struct {}
func (*testStruct) DoSomething(context.Context){}
func (*testStruct) DoSomethingElse([]byte){}
func main() {
structType := reflect.TypeOf(&testStruct{})
for i := 0; i < structType.NumMethod(); i++ {
fmt.Println("======================")
method := structType.Method(i)
fmt.Println(method.Name)
fmt.Println(method.Type.String())
// compare method and Fn signature
}
}
https://play.golang.org/p/rIDfp0E14ge
1. Using reflect.Value.Type().ConvertibleTo
Note the reflect.ValueOf insted of reflect.TypeOf
package main
import (
"context"
"fmt"
"reflect"
)
type Fn func(context.Context)
type testStruct struct{}
func (*testStruct) DoSomething(context.Context) {}
func (*testStruct) DoSomethingElse([]byte) {}
func (*testStruct) DoSomethingElse2(context.Context) error { return nil }
func main() {
structType := reflect.ValueOf(&testStruct{})
for i := 0; i < structType.NumMethod(); i++ {
fmt.Println("======================")
method := structType.Method(i)
// compare method and Fn
if method.Type().ConvertibleTo(reflect.TypeOf((Fn)(nil))) {
fmt.Println("function of correct type")
}
}
}
https://play.golang.org/p/A9_bpURinad
2. Checking inputs and outputs individually
package main
import (
"context"
"fmt"
"reflect"
)
type Fn func(context.Context)
type testStruct struct{}
func (*testStruct) DoSomething(context.Context) {}
func (*testStruct) DoSomethingElse([]byte) {}
func main() {
structType := reflect.TypeOf(&testStruct{})
rctx := reflect.TypeOf(new(context.Context)).Elem()
for i := 0; i < structType.NumMethod(); i++ {
fmt.Println("======================")
method := structType.Method(i)
fmt.Println(method.Name)
fmt.Println(method.Type.String())
if method.Type.NumIn() != 2 {
fmt.Println("wrong number of inputs, expected 1")
continue
}
if method.Type.In(1) != rctx {
fmt.Println("input of wrong type, expected context.Context")
continue
}
if method.Type.NumOut() != 0 {
fmt.Println("wrong number of outputs, expected 0")
continue
}
fmt.Printf("%v is a function of correct type\n", method.Name)
}
}
https://play.golang.org/p/YDsJ9MSiumF

Go - Append to []interface{} via reflection

Without reflection it is possible to add multiple types to a list of type []interface{}. Like so:
package main
import "fmt"
func main() {
var foo []interface{}
foo = append(foo, "Test")
foo = append(foo, "Foo")
foo = append(foo, 10)
fmt.Printf("%v\n", foo)
}
Is this possible with reflection? I try the following but I get a panic saying: "panic: reflect.Set: value of type string is not assignable to type []interface {}"
package main
import (
"fmt"
"reflect"
)
func rf(inf interface{}) {
val := reflect.Indirect(reflect.ValueOf(inf))
field := val.FieldByName("Foo")
rslice := reflect.MakeSlice(reflect.SliceOf(field.Type()), 0, 5)
v := reflect.Indirect(reflect.ValueOf("Test"))
rslice = reflect.Append(rslice, v)
}
func main() {
var s struct {
Foo []interface{}
}
rf(&s)
fmt.Printf("%+v\n", s)
}
The Foo field is already of type []interface{}, so SliceOf is creating a [][]interface{}, which is what causes the error you see.
Remove the SliceOf, and then use field.Set(rslice) to set the new value back to the struct field.
func rf(inf interface{}) {
val := reflect.Indirect(reflect.ValueOf(inf))
field := val.FieldByName("Foo")
rslice := reflect.MakeSlice(field.Type(), 0, 5)
v := reflect.Indirect(reflect.ValueOf("Test"))
rslice = reflect.Append(rslice, v)
field.Set(rslice)
}
http://play.golang.org/p/gWK3-cP_MN

In go (golang), how can you cast an interface pointer into a struct pointer?

I want to use some external code that requires a pointer to a struct. At the point that the code is called, I have an interface variable.
When creating a pointer off of that variable, the pointer's type is interface{}* when I need it to be the pointer type of the struct's type.
Image the code in TestCanGetStructPointer does not know about the Cat class, and that it exists in some external package.
How can I cast it to this?
Here is a code sample:
import (
"reflect"
"testing"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func TestCanGetStructPointer(t *testing.T) {
interfaceVariable := somethingForCats.getSomething()
pointer := &interfaceVariable
interfaceVarType := reflect.TypeOf(interfaceVariable)
structPointerType := reflect.PtrTo(interfaceVarType)
pointerType := reflect.TypeOf(pointer)
if pointerType != structPointerType {
t.Errorf("Pointer type was %v but expected %v", pointerType, structPointerType)
}
}
The test fails with:
Pointer type was *interface {} but expected *parameterized.Cat
#dyoo's example does work, but it relies on you to manually cast Dog and Cat.
Here's a bit of a convoluted/verbose example which avoids that constraint somewhat:
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "Fuzzy Wuzzy"}
}
var somethingForCats = SomethingGeneric{getSomething: getSomeCat}
func main() {
interfaceVariable := somethingForCats.getSomething()
castVar := reflect.ValueOf(interfaceVariable)
castVar.Convert(castVar.Type())
// If you want a pointer, do this:
fmt.Println(reflect.PtrTo(castVar.Type()))
// The deref'd val
if castVar.Type() != reflect.TypeOf(Cat{}) {
fmt.Printf("Type was %v but expected %v\n", castVar, reflect.TypeOf(&Cat{}))
} else {
fmt.Println(castVar.Field(0))
}
}
Playground Link
I found this thread: https://groups.google.com/forum/#!topic/golang-nuts/KB3_Yj3Ny4c
package main
import (
"fmt"
"reflect"
)
type Cat struct {
name string
}
//
// Return a pointer to the supplied struct via interface{}
//
func to_struct_ptr(obj interface{}) interface{} {
fmt.Println("obj is a", reflect.TypeOf(obj).Name())
// Create a new instance of the underlying type
vp := reflect.New(reflect.TypeOf(obj))
// Should be a *Cat and Cat respectively
fmt.Println("vp is", vp.Type(), " to a ", vp.Elem().Type())
vp.Elem().Set(reflect.ValueOf(obj))
// NOTE: `vp.Elem().Set(reflect.ValueOf(&obj).Elem())` does not work
// Return a `Cat` pointer to obj -- i.e. &obj.(*Cat)
return vp.Interface()
}
//
// Dump out a pointer ...
//
func test_ptr(ptr interface{}) {
v := reflect.ValueOf(ptr)
fmt.Println("ptr is a", v.Type(), "to a", reflect.Indirect(v).Type())
}
func main() {
cat := Cat{name: "Fuzzy Wuzzy"}
// Reports "*main.Cat"
test_ptr(&cat)
// Get a "*Cat" generically via interface{}
sp := to_struct_ptr(cat)
// *should* report "*main.Cat" also
test_ptr(sp)
fmt.Println("sp is",sp)
}
The following may help: http://play.golang.org/p/XkdzeizPpP
package main
import (
"fmt"
)
type Cat struct {
name string
}
type Dog struct {
name string
}
type SomethingGeneric struct {
getSomething func() interface{}
}
func getSomeCat() interface{} {
return Cat{name: "garfield"}
}
func getSomeDog() interface{} {
return Dog{name: "fido"}
}
var somethings = []SomethingGeneric{
SomethingGeneric{getSomething: getSomeCat},
SomethingGeneric{getSomething: getSomeDog},
}
func main() {
for _, something := range somethings {
interfaceVariable := something.getSomething()
cat, isCat := interfaceVariable.(Cat)
dog, isDog := interfaceVariable.(Dog)
fmt.Printf("cat %v %v\n", cat, isCat)
fmt.Printf("dog %v %v\n", dog, isDog)
}
}

How to use pointer type in struct initializer?

I cannot figure out how to initialize structure field when it is a reference type alias of the one of the number types:
package main
import (
"fmt"
"encoding/json"
)
type Nint64 *int64
type MyStruct struct {
Value Nint64
}
func main() {
data, _ := json.Marshal(&MyStruct{ Value : ?? 10 ?? })
fmt.Println(string(data))
}
You can't, you will have to add an extra step playground:
func NewMyStruct(i int64) *MyStruct {
return &MyStruct{&i}
}
func main() {
i := int64(10)
data, _ := json.Marshal(&MyStruct{Value: Nint64(&i)})
fmt.Println(string(data))
//or this
data, _ = json.Marshal(NewMyStruct(20))
fmt.Println(string(data))
}
I don't think you want to reference to the address of an int64 ...
package main
import (
"encoding/json"
"fmt"
)
type Nint64 int64
type MyStruct struct {
Value Nint64
}
func main() {
data, _ := json.Marshal(&MyStruct{Value: Nint64(10)})
fmt.Println(string(data))
}
http://play.golang.org/p/xafMLb_c73

Resources