Getting substruct field in Go - go

I am trying to get fields from a struct value using reflection.
package main
import (
"fmt"
"reflect"
)
type Vertex struct {
X string
Y string
SubVertex SubVertex
}
type SubVertex struct {
Z string
}
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
func main() {
v := Vertex{"a", "b", SubVertex{"c"}}
fmt.Println(get_field(v, "X"))
fmt.Println(get_field(v, "Y"))
fmt.Println(get_field(v, "Z")) // Invalid Value
}
I get Invalid Value in the third case, when I try to get the value of the Z field. If SubVertex were an anonymous field, this would work, but I need to use a named field.
How do I make this work?

In this case, you have to use the reflect package in the same manner as you would accessing the values normally. So
v.X // a
v.Y // b
v.SubVertex.Z // c
becomes
r := reflect.ValueOf(v)
x := reflect.Indirect(r).FieldByName("X")
x.String() // a
...
z := reflect.Indirect(r).FieldByName("SubVertex").FieldByName("Z")
z.String() // c
Note that FieldByName() is called on a Value and returns a Value, so it works much the same as just accessing it regularly. Also note that as per the documentation:
Indirect returns the value that v points to. If v is a nil pointer, Indirect returns a zero Value. If v is not a pointer, Indirect returns v.
So the call to Indirect() would be a No-op, but would protect it from having a meltdown if you decided to give it a pointer in the future.
As for your function, this would work
func get_field(v Vertex, field string) string {
r := reflect.ValueOf(v)
if field == "Z" {
f := reflect.Indirect(r).FieldByName("SubVertex").FieldByName(field)
return f.String()
}
f := reflect.Indirect(r).FieldByName(field)
return f.String()
}
https://play.golang.org/p/eZyTl8OSTZ

Related

Go: A function that would consume maps with different types of values

In my code, I need a function that would return an ordered slice of keys from a map.
m1 := make(map[string]string)
m2 := make(map[string]int)
And now I need to call a function passing both types of maps:
keys1 := sortedKeys(m1)
keys2 := sortedKeys(m1)
Problem: I have to write two functions because the function should consume maps of two different types. At the same time, the body of the function will be the same in both cases.
Question: How can I use a single implementation for two maps? Or is there any other way of solving the problem in an elegant way?
My first idea was to use map[string]interface{} as an argument type, but you can't assign neither map[string]string, nor map[string]int to it.
My code:
func sortedKeys(m map[string]string) []string {
var keys []string
for key := range m {
keys = append(keys, key)
}
sort.Strings(keys)
return keys
}
I would have to repeat the same code but for map[string]int.
You can use interface{} and use reflection for achieving this.
You can write two functions for the same but it is just not scalable, say, you are supporting string and int now but you wish to support int64, float64, bool or struct in the future. Having a common function using map[string]interface{} and using reflection is the way to go.
Suggested Code :
package main
import (
"fmt"
"reflect"
)
func main() {
m1 := make(map[string]string)
m2 := make(map[string]int)
m1["a"] = "b"
m1["b"] = "c"
m2["a"] = 1
m2["b"] = 2
fmt.Println(sortedKeys(m1))
fmt.Println(sortedKeys(m2))
}
// Returns slice of values in the type which is sent to it
func sortedKeys(m interface{}) interface{} {
if m == nil {
return nil
}
if reflect.TypeOf(m).Kind() != reflect.Map {
return nil
}
mapIter := reflect.ValueOf(m).MapRange()
mapVal := reflect.ValueOf(m).Interface()
typ := reflect.TypeOf(mapVal).Elem()
outputSlice := reflect.MakeSlice(reflect.SliceOf(typ), 0, 0)
for mapIter.Next() {
outputSlice = reflect.Append(outputSlice, mapIter.Value())
}
return outputSlice.Interface()
}
Output :
[b c]
[1 2]
https://play.golang.org/p/2fkpydH9idG

How to access unexported struct fields

Is there a way to use reflect to access unexported fields in Go 1.8?
This no longer seems to work: https://stackoverflow.com/a/17982725/555493
Note that reflect.DeepEqual works just fine (that is, it can access unexported fields) but I can't make heads or tails of that function. Here's a go playarea that shows it in action: https://play.golang.org/p/vyEvay6eVG. The src code is below
import (
"fmt"
"reflect"
)
type Foo struct {
private string
}
func main() {
x := Foo{"hello"}
y := Foo{"goodbye"}
z := Foo{"hello"}
fmt.Println(reflect.DeepEqual(x,y)) //false
fmt.Println(reflect.DeepEqual(x,z)) //true
}
If the struct is addressable, you can use unsafe.Pointer to access the field (read or write) it, like this:
rs := reflect.ValueOf(&MyStruct).Elem()
rf := rs.Field(n)
// rf can't be read or set.
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read and set.
See full example on the playground.
This use of unsafe.Pointer is valid according to the documentation and running go vet returns no errors.
If the struct is not addressable this trick won't work, but you can create an addressable copy like this:
rs = reflect.ValueOf(MyStruct)
rs2 := reflect.New(rs.Type()).Elem()
rs2.Set(rs)
rf = rs2.Field(0)
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
// Now rf can be read. Setting will succeed but only affects the temporary copy.
See full example on the playground.
Based on cpcallen's work:
import (
"reflect"
"unsafe"
)
func GetUnexportedField(field reflect.Value) interface{} {
return reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).Elem().Interface()
}
func SetUnexportedField(field reflect.Value, value interface{}) {
reflect.NewAt(field.Type(), unsafe.Pointer(field.UnsafeAddr())).
Elem().
Set(reflect.ValueOf(value))
}
reflect.NewAt might be confusing to read at first. It returns a reflect.Value representing a pointer to a value of the specified field.Type(), using unsafe.Pointer(field.UnsafeAddr()) as that pointer. In this context reflect.NewAt is different than reflect.New, which would return a pointer to a freshly initialized value.
Example:
type Foo struct {
unexportedField string
}
GetUnexportedField(reflect.ValueOf(&Foo{}).Elem().FieldByName("unexportedField"))
https://play.golang.org/p/IgjlQPYdKFR
reflect.DeepEqual() can do it because it has access to unexported features of the reflect package, in this case namely for the valueInterface() function, which takes a safe argument, which denies access to unexported field values via the Value.Interface() method if safe=true. reflect.DeepEqual() will (might) call that passing safe=false.
You can still do it, but you cannot use Value.Interface() for unexported fields. Instead you have to use type-specific methods, such as Value.String() for string, Value.Float() for floats, Value.Int() for ints etc. These will return you a copy of the value (which is enough to inspect it), but will not allow you to modify the field's value (which might be "partly" possible if Value.Interface() would work and the field type would be a pointer type).
If a field happens to be an interface type, you may use Value.Elem() to get to the value contained / wrapped by the interface value.
To demonstrate:
type Foo struct {
s string
i int
j interface{}
}
func main() {
x := Foo{"hello", 2, 3.0}
v := reflect.ValueOf(x)
s := v.FieldByName("s")
fmt.Printf("%T %v\n", s.String(), s.String())
i := v.FieldByName("i")
fmt.Printf("%T %v\n", i.Int(), i.Int())
j := v.FieldByName("j").Elem()
fmt.Printf("%T %v\n", j.Float(), j.Float())
}
Output (try it on the Go Playground):
string hello
int64 2
float64 3
package main
import (
"fmt"
"reflect"
"strings"
"unsafe"
)
type Person1 struct {
W3ID string
Name string
}
type Address1 struct {
city string
country string
}
type User1 struct {
name string
age int
address Address1
manager Person1
developer Person1
tech Person1
}
func showDetails(load, email interface{}) {
if reflect.ValueOf(load).Kind() == reflect.Struct {
typ := reflect.TypeOf(load)
value := reflect.ValueOf(load)
//#1 For struct, not addressable create a copy With Element.
value2 := reflect.New(value.Type()).Elem()
//#2 Value2 is addressable and can be set
value2.Set(value)
for i := 0; i < typ.NumField(); i++ {
if value.Field(i).Kind() == reflect.Struct {
rf := value2.Field(i)
/* #nosec G103 */
rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
irf := rf.Interface()
typrf := reflect.TypeOf(irf)
nameP := typrf.String()
if strings.Contains(nameP, "Person") {
//fmt.Println(nameP, "FOUND !!!!!!! ")
for j := 0; j < typrf.NumField(); j++ {
re := rf.Field(j)
nameW := typrf.Field(j).Name
if strings.Contains(nameW, "W3ID") {
valueW := re.Interface()
fetchEmail := valueW.(string)
if fetchEmail == email {
fmt.Println(fetchEmail, " MATCH!!!!")
}
}
}
}
showDetails(irf, email)
} else {
// fmt.Printf("%d.Type:%T || Value:%#v\n",
// (i + 1), value.Field(i), value.Field(i))
}
}
}
}
func main() {
iD := "tsumi#in.org.com"
load := User1{
name: "John Doe",
age: 34,
address: Address1{
city: "New York",
country: "USA",
},
manager: Person1{
W3ID: "jBult#in.org.com",
Name: "Bualt",
},
developer: Person1{
W3ID: "tsumi#in.org.com",
Name: "Sumi",
},
tech: Person1{
W3ID: "lPaul#in.org.com",
Name: "Paul",
},
}
showDetails(load, iD)
}

Modify array of interface{} golang

This type assertion, def-referencing has been driving me crazy. So I have a nested structure of Key string / Value interface{} pairs. Stored in the Value is an []interface which I want to modify each of the values. Below is an example of creating an array of Bar and passing it into the ModifyAndPrint function which should modify the top level structure. The problem that I come accross is as written it doesn't actually modify the contents of z, and I can't do a q := z.([]interface{})[i].(Bar) or & thereof.
Is there a way to do this? If so, what combination did I miss?
package main
import "fmt"
type Bar struct {
Name string
Value int
}
func ModifyAndPrint(z interface{}){
fmt.Printf("z before: %v\n", z)
for i, _ := range(z.([]interface{})) {
q := z.([]interface{})[i]
b := (q).(Bar)
b.Value = 42
fmt.Printf("Changed to: %v\n", b)
}
fmt.Printf("z after: %v\n", z)
}
func main() {
bars := make([]interface{}, 2)
bars[0] = Bar{"a",1}
bars[1] = Bar{"b",2}
ModifyAndPrint(bars)
}
https://play.golang.org/p/vh4QXS51tq
The program is modifying a copy of the value in the interface{}. One way to achieve your goal is to assign the modified value back to the slice:
for i, _ := range(z.([]interface{})) {
q := z.([]interface{})[i]
b := (q).(Bar)
b.Value = 42
z.([]interface{})[i] = b
fmt.Printf("Changed to: %v\n", b)
}
playground example

golang - reflection on embedded structs

Given a struct like so:
type B struct {
X string
Y string
}
type D struct {
B
Z string
}
I want to reflect on D and get to the fields X, Y, Z.
Intuitively, before attempting the solution, I was assuming I would be able to traverse the struct D and get all fields using reflection (X, Y, Z) and won't have to deal with B.
But as you can see, I only see the embedded struct B using reflection and not its fields.
http://play.golang.org/p/qZQD5GdTA8
Is there a way I can make B fully transparent when reflecting on D?
Why do I want this?
Imaging a common struct (B in the example here), that is used in multiple other structs by using embedding. Using reflection, the attempt is to copy D into another similar struct in a different package. The destination struct for copying will have all attributes flatly laid out (no embedding there). So there is a mismatch from the source to the destination (embedding vs no embedding) but all the attributes flatly laid out are the same. I don't want to create custom solutions for each struct.
The 'transparency' you expected is just syntactic sugar and has nothing to do with the data representation. If you want to have a function that flattens your data structure, you would have to write it by yourself.
For example (On play):
func DeepFields(iface interface{}) []reflect.Value {
fields := make([]reflect.Value, 0)
ifv := reflect.ValueOf(iface)
ift := reflect.TypeOf(iface)
for i := 0; i < ift.NumField(); i++ {
v := ifv.Field(i)
switch v.Kind() {
case reflect.Struct:
fields = append(fields, DeepFields(v.Interface())...)
default:
fields = append(fields, v)
}
}
return fields
}
Use the following code to collect all promoted field names as keys in map m:
func collectFieldNames(t reflect.Type, m map[string]struct{}) {
// Return if not struct or pointer to struct.
if t.Kind() == reflect.Ptr {
t = t.Elem()
}
if t.Kind() != reflect.Struct {
return
}
// Iterate through fields collecting names in map.
for i := 0; i < t.NumField(); i++ {
sf := t.Field(i)
m[sf.Name] = struct{}{}
// Recurse into anonymous fields.
if sf.Anonymous {
collectFieldNames(sf.Type, m)
}
}
}
Use it like this:
m := make(map[string]struct{})
collectFieldNames(reflect.TypeOf((*D)(nil)), m)
for name := range m {
fmt.Println(name)
}
Run it on the playground.
This program prints X, Y an Z as requested in the question, but also B because B is also a field name.
This function in this answer can be improved:
Don't blow up on recursive type definitions.
Do not include names repeated at the same level in the hierarchy.
The typeField function in encoding/json/encode.go handles both of these issues.

golang - Pointer idiosyncrasies

Need help understanding why this breaks. PrintFoo can be called using either pointer or value. Why not NumField?
http://play.golang.org/p/Kw16ReujRx
type A struct {
foo string
}
func (a *A) PrintFoo(){
fmt.Println("Foo value is " + a.foo)
}
func main() {
a := &A{foo: "afoo"}
(*a).PrintFoo() //Works - no problem
a.PrintFoo() //Works - no problem
reflect.TypeOf(*a).NumField() //Works - no problem - Type = main.A
reflect.TypeOf(a).NumField() //BREAKS! - Type = *main.A
}
From the documentation :
// NumField returns the number of fields in the struct v.
// It panics if v's Kind is not Struct.
func (v Value) NumField() int
You are calling it on a pointer, you have to call it on a struct instead, for example :
fmt.Println(reflect.Indirect(reflect.ValueOf(a)).NumField())
fmt.Println(reflect.Indirect(reflect.ValueOf(*a)).NumField())
When you're not sure if your value is a pointer or not, use reflect.Indirect:
Indirect returns the value that v points to. If v is a nil pointer,
Indirect returns a zero Value. If v is not a pointer, Indirect returns
v.
//edit:
NumField gets called on Value, not your actual object, for example of you do:
func main() {
a := &A{foo: "afoo"}
fmt.Printf("%#v\n", reflect.TypeOf(*a))
fmt.Printf("%#v\n", reflect.TypeOf(a))
}
You will get :
//*a
&reflect.rtype{size:0x8, ...... ptrToThis:(*reflect.rtype)(0xec320)}
//a
&reflect.rtype{size:0x4, ...... ptrToThis:(*reflect.rtype)(nil)}
As you can tell, it's a completely different beast.
The first one holds information about the pointer, hence ptrToThis points to the actual struct.
The second holds info about the struct itself.

Resources