How do I use reflection to get slice data? - go

package main
import (
"fmt"
"reflect"
)
//AuthRequest struct
type AuthRequest struct {
Id int64
}
func main() {
//AuthRequest auth1
auth1 := AuthRequest{
Id : 1111,
}
//Authrequest auth2
auth2 := AuthRequest{
Id : 2222,
}
//create slice
var sliceModel = make([]AuthRequest, 0)
//put element to slice
sliceModel = append(sliceModel, auth1)
sliceModel = append(sliceModel, auth2)
//Pointer to an array
model := &sliceModel
//How do I get the struct Id field here?
v := reflect.ValueOf(model).Elem()
for j := 0; j < v.NumField(); j++ {
f := v.Field(j)
n := v.Type().Field(j).Name
t := f.Type().Name()
fmt.Printf("Name: %s Kind: %s Type: %s\n", n, f.Kind(), t)
}
}
When I execute the above code, I get the following error.
panic: reflect: call of reflect.Value.NumField on slice Value [recovered]
How do I use reflection to traverse slice to get the value of Id field in the struct AuthRequest?

From the docs:
NumField returns the number of fields in the struct v. It panics if v's Kind is not Struct.
Since your input is a slice, not a struct, NumField is supposed to panic.
You probably need the Slice method.

Related

How to get the element type of slice?

If there is a struct like:
type A struct {
Arr []int
}
How can I get the element type in the slice arr?
for example, an empty A instance is passed in, how can I get the int type?
func PrintElementType(obj interface{}) {
objType := reflect.TypeOf(obj)
for i := 0; i < objType.NumField(); i++ {
fieldType := objType.Field(i).Type
// here I got 'slice'
fmt.Println(fieldType.Kind())
// here I got '[]int', I think 'int' type is stored somewhere...
fmt.Println(fieldType)
// so, is there any way to get 'int' type?
fmt.Println("inner element type?")
}
}
func main() {
a := A{}
PrintElementType(a)
}
If you have the reflect.Type type descriptor of a slice type, use its Type.Elem() method to get the type descriptor of the slice's element type:
fmt.Println(fieldType.Elem())
Type.Elem() may also be used to get the element type if the type's Kind is Array, Chan, Map, Ptr, or Slice, but it panics otherwise. So you should check the kind before calling it:
if fieldType.Kind() == reflect.Slice {
fmt.Println("Slice's element type:", fieldType.Elem())
}
This will output (try it on the Go Playground):
slice
[]int
Slice's element type: int

reflect runtime error: call of reflect.flag.mustBeAssignable on zero Value

I'm testing this code snippet on go playground, I aim to use reflect to get fields from one object, and then set value to another object
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"testaaa"`
B string `json:"bbb" test:"testbbb"`
}
type newT struct {
AA int
BB string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("newT")
tValue := tv.Field(i)
newTValue.Elem().FieldByName(newTTag).Set(tValue)
}
fmt.Println(newT)
}
And it gives a very strange error:
panic: reflect: call of reflect.flag.mustBeAssignable on zero Value
goroutine 1 [running]:
reflect.flag.mustBeAssignableSlow(0x0, 0x0)
/usr/local/go/src/reflect/value.go:240 +0xe0
reflect.flag.mustBeAssignable(...)
/usr/local/go/src/reflect/value.go:234
reflect.Value.Set(0x0, 0x0, 0x0, 0x100f80, 0x40a0f0, 0x82)
/usr/local/go/src/reflect/value.go:1531 +0x40
main.main()
/tmp/sandbox166479609/prog.go:32 +0x400
Program exited: status 2.
How to fix it?
It is as error call of reflect.flag.mustBeAssignable on zero Value says , newTValue.Elem().FieldByName(newTTag).CanSet() returns false in your your code and according to documentation
Set assigns x to the value v. It panics if CanSet returns false. As in Go, x's value must be assignable to v's type.
This is corrected code that takes fields from one Object and assigns value to another one.
package main
import (
"fmt"
"reflect"
)
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
type newT struct {
AA int
BB string
Testaaa string
}
func main() {
t := T{
A: 123,
B: "hello",
}
tt := reflect.TypeOf(t)
tv := reflect.ValueOf(t)
newT := &newT{}
newTValue := reflect.ValueOf(newT)
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
fmt.Println(newT)
}
First:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
Each step here iterates through the fields of your instance of type T. So the fields will be A—or rather, the field descriptor whose Name is A and which describes an int with its json and test tags—and then B (with the same picky details if we go any further).
Since both field descriptors have only two Get-able items, you probably meant to use Get("test"), as in Guarav Dhiman's answer.
If you do that, though, the result is "testaaa" when you are on field A and "testbbb" when you are on field B. If we annotate Guarav's code a bit more:
for i := 0; i < tt.NumField(); i++ {
field := tt.Field(i)
newTTag := field.Tag.Get("test")
fmt.Printf("newTTag = %#v\n", newTTag)
tValue := tv.Field(i)
newTfield := newTValue.Elem().FieldByName(newTTag)
fmt.Printf("newTfield = %#v\n", newTfield)
if newTfield.CanSet() {
newTfield.Set(tValue)
}
}
we will see this output:
newTTag = "testaaa"
newTfield = <invalid reflect.Value>
newTTag = "testbbb"
newTfield = <invalid reflect.Value>
What we need is to make the test string in each tag name the field in the newT type:
type T struct {
A int `json:"aaa" test:"AA"`
B string `json:"bbb" test:"BB"`
}
(Guarav actually already did this but did not mention it.) Now the program produces what (presumably) you intended:
&{123 hello}
The complete program, with commented-out tracing, is here.

What's the difference between Type.Field and Value.Field?

Following code.
func fieldsTest(target interface{}) ([]field, error) {
s := reflect.ValueOf(target)
s = s.Elem()
targetType := s.Type()
for i := 0; i < s.NumField(); i++ {
f := s.Field(i)
structField := targetType.Field(i)
...
}
If the target interface is a struct, the return value of f are the same as structField?
Type.Field() returns a value of type reflect.StructField, and Value.Field() returns a value of type reflect.Value. So they cannot be the same.
Type.Field() returns a value describing the field's type, regardless of any actual struct value. Value.Field() returns a reflect.Value that wraps the value of a field of a struct value.

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

Why Golang object property of byte array will be wiped when assigned to another variable

We need to wipe out some variables after use. But it seems really weird when it's assigned with a []byte field in a struct.
Why this assignment of []byte is not a copy but a pointer?
What should I do to keep the value in struct a.bs, but wipe out the b as local variable?
http://play.golang.org/p/MT_wAHj2OM
package main
import "fmt"
type so struct {
bs []byte
}
func zeroes(n int) []byte {
return make([]byte, n)
}
func wipeBytes(b []byte) {
copy(b, zeroes(len(b)))
}
func main() {
a := so{bs: []byte{0x01, 0x02}}
b := a.bs
wipeBytes(b)
fmt.Println(b) //b == []byte{}
fmt.Println(a.bs) //a.bs == []byte{}
}
Slices are inherently reference-y things. Assigning one doesn't copy its contents. You can think of a slice value as being a "slice head" structure, which contains a pointer to the slice's underlying array, and the offset and length of the slice within the array. It's this structure that's copied when you copy the slice, not any of the values in the array.
You can do
b := make([]byte, len(a.bs)))
copy(b, a.bs)
to make b a new slice and copy a.bs's contents into it. Then nothing you do to one will have any effect on the other.
When declaring/creating the 'array' ([]byte{0x01, 0x02}), you're not specifying a length ([2]byte{0x01, 0x02}), which means that it's a slice instead of an array. And slices objects internally contains a pointer to it's content.
func ObjectAssign(target interface{}, object interface{}) {
// object atributes values in target atributes values
// using pattern matching (https://golang.org/pkg/reflect/#Value.FieldByName)
// https://stackoverflow.com/questions/35590190/how-to-use-the-spread-operator-in-golang
t := reflect.ValueOf(target).Elem()
o := reflect.ValueOf(object).Elem()
for i := 0; i < o.NumField(); i++ {
for j := 0; j < t.NumField(); j++ {
if t.Field(j).Name() == o.Field(i).Name() {
t.Field(j).Set(o.Field(i))
}
}
}
}

Resources