Check if a slice contains a struct with a given field value - go

Trying to check if a struct in some slice contains a value of a given field so i wrote this
func main() {
//test
Objs := []Obj{{1,"xxx"},{2,"yyy"},{3,"zzz"}}
res := containsStructFieldValue(Objs,"X",1)
fmt.Println(res)
}
type Obj struct {
X int
Y string
}
func containsStructFieldValue(slice []Obj ,fieldName string,fieldValueToCheck interface {}) bool{
for _,s := range slice{
r := reflect.ValueOf(s)
f := r.FieldByName(fieldName)
if f.IsValid(){
if f.Interface() == fieldValueToCheck{
return true //a field with the given value exists
}
}
}
return false
}
i need it to work for any given struct type but when i tried slice []interface as the parameter i found out that its not possible, any idea on how to make the above method work for any struct type?

You can use reflect to range over an interface{}, for instance:
func containsStructFieldValue(slice interface{} ,fieldName string,fieldValueToCheck interface {}) bool{
rangeOnMe := reflect.ValueOf(slice)
for i := 0; i < rangeOnMe.Len(); i++ {
s := rangeOnMe.Index(i)
f := s.FieldByName(fieldName)
if f.IsValid(){
if f.Interface() == fieldValueToCheck {
return true
}
}
}
}
Note that I did not check that slice is indeed a slice... If not, this code will panic. You can use reflect.Kind to check this if you want to avoid this behaviour.

Related

Type that describes any go function

I want to write a function that partially applies a function to an argument, like this:
func partial(f AnyFuncType, arg interface{}) AnyFuncType {
return func(args ...interface{}) interface{} {
return f(arg, args)
}
}
type AnyFuncType func(args ...interface{}) interface{}
But that doesn't work even with the simplest function like that
func sum(a int, b int) int {
return a + b
}
func main() {
addToFive := partial(sum, 5)
}
because I get
./prog.go:16:23: cannot use sum (type func(int, int) int) as type AnyFuncType in argument to partial
compilation error. Now, I know that I could use interface{}, but is there a way to specify a more precise type for f that would work with any function?
You are trying to treat interface{} as a generic type, but interface{} is not a generic type and go will not match the signature of a function that takes interface{} as the signature of a function that takes a concrete type.
The problem is, subtyping in GO works only for interaces. Since AnyFuncType is not an interface, this won't work.
Use interface{} to represent a function of any type. There is not a more precise type that works with any function.
Use the reflect package to implement partial.
func partial(f interface{}, arg interface{}) interface{} {
v := reflect.ValueOf(f)
t := v.Type()
var in []reflect.Type
for i := 1; i < t.NumIn(); i++ {
in = append(in, t.In(i))
}
var out []reflect.Type
for i := 0; i < t.NumOut(); i++ {
out = append(out, t.Out(i))
}
var va reflect.Value
if arg != nil {
va = reflect.ValueOf(arg)
} else {
// Support `nil` as partial argument.
va = reflect.Zero(t.In(0))
}
return reflect.MakeFunc(reflect.FuncOf(in, out, t.IsVariadic()),
func(args []reflect.Value) []reflect.Value {
return v.Call(append([]reflect.Value{va}, args...))
}).Interface()
}
Use it like this:
addToFive := partial(sum, 5).(func(int) int)
fmt.Println(addToFive(1))
Run it on the playground.
I recommend using a closure to create partials instead of the partial function in this answer. The closure is more efficient and avoids tricky reflect code.
addToFive := func(x int) int { return sum(5, x) }
fmt.Println(addToFive(1))

Lookup a tag by field symbol in Go

Given a structure with fields I'd like to lookup tag value for particular field symbolically (without providing field name as string).
type MyStruct struct {
Foo string `tag:"val"`
}
entity := MyStruct{}
tagVal := getTag(&entity.Foo) // the function would return "val" for Foo field
I'd like to implement a getTag function that would return tag value for a given field.
Pointer to field value does no contain any information about owner structure, that's a different way of indirection, so having only a pointer field value is not enough to solve the problem.
One solution could be to use pointer to owner structure together with pointer to the field in that structure, iterate fields of that structure value with reflection until the address of iterated field matches given field value pointer.
https://play.golang.org/p/kaPQ9HF9wAK
package main
import (
"fmt"
"reflect"
)
func main() {
type MyStruct struct {
Foo string `tag:"val"`
}
entity := MyStruct{}
tagVal := getTag(&entity, &entity.Foo)
fmt.Println(tagVal) // val
}
func getTag(structPtr, fieldPtr interface{}) string {
sf, ok := structFieldByValPtr(structPtr, fieldPtr)
if !ok {
return ""
}
return sf.Tag.Get("tag")
}
func structFieldByValPtr(structPtr, fieldPtr interface{}) (reflect.StructField, bool) {
v := reflect.Indirect(reflect.ValueOf(structPtr))
t := v.Type()
for i := 0; i < v.NumField(); i++ {
fv := v.Field(i)
ft := t.Field(i)
if fv.Addr().Interface() == fieldPtr {
return ft, true
}
if ft.Anonymous {
sf, ok := structFieldByValPtr(fv.Addr().Interface(), fieldPtr)
if ok {
return sf, true
}
}
}
return reflect.StructField{}, false
}

How to copy a non-pointer value to a pointer indirected value via reflection

I want the Set method below to set the APtr field of a passed in B struct to a value that gets passed in by value, i.e. without a pointer indirection.
For that to work via go reflection, I will probably have to copy that value to a new location that I have the address of? Either way, how can I get this to work? What I have is a working version for non-pointers values.
type A struct {
AnInt int
}
type B struct {
AnA A
APtr *A
}
func Set(strukt interface{}, fieldName string, newFieldValue interface{}) {
struktValueElem := reflect.ValueOf(strukt).Elem()
field := struktValueElem.FieldByName(fieldName)
newFieldValueValue := reflect.ValueOf(newFieldValue)
if field.Kind() == reflect.Ptr {
// ?? implement me
} else { // not a pointer? more straightforward:
field.Set(newFieldValueValue)
}
}
func main() {
aB := B{}
anA := A{4}
Set(&aB, "AnA", anA) // works
Set(&aB, "APtr", anA) // implement me
}
Playground: https://play.golang.org/p/6tcmbXxBcIm
func Set(strukt interface{}, fieldName string, newFieldValue interface{}) {
struktValueElem := reflect.ValueOf(strukt).Elem()
field := struktValueElem.FieldByName(fieldName)
newFieldValueValue := reflect.ValueOf(newFieldValue)
if field.Kind() == reflect.Ptr {
rt := field.Type() // type *A
rt = rt.Elem() // type A
rv := reflect.New(rt) // value *A
el := rv.Elem() // value A (addressable)
el.Set(newFieldValueValue) // el is addressable and has the same type as newFieldValueValue (A), Set can be used
field.Set(rv) // field is addressable and has the same type as rv (*A), Set can be used
} else { // not a pointer? more straightforward:
field.Set(newFieldValueValue)
}
}
https://play.golang.org/p/jgEK_rKbgO9
https://play.golang.org/p/B6vOONQ-RXO (compact)

Is it possible to use reflected array type in Golang type assertions?

I need to check if interface{} is an array and create corresponding slice if it is. Unfortunately I do not know array length in advance.
For example:
import (
"reflect"
)
func AnythingToSlice(a interface{}) []interface{} {
rt := reflect.TypeOf(a)
switch rt.Kind() {
case reflect.Slice:
slice, ok := a.([]interface{})
if ok {
return slice
}
// it works
case reflect.Array:
// return a[:]
// it doesn't work: cannot slice a (type interface {})
//
array, ok := a.([reflect.ValueOf(a).Len()]interface{})
// :-((( non-constant array bound reflect.ValueOf(a).Len()
if ok {
return array[:]
}
}
return []interface{}(a)
}
An explicit type is required in a type assertion. The type cannot be constructed through reflection.
Unless the argument is a []interface{}, the slice or array must be copied to produce a []interface{}.
Try this:
func AnythingToSlice(a interface{}) []interface{} {
v := reflect.ValueOf(a)
switch v.Kind() {
case reflect.Slice, reflect.Array:
result := make([]interface{}, v.Len())
for i := 0; i < v.Len(); i++ {
result[i] = v.Index(i).Interface()
}
return result
default:
panic("not supported")
}
}
https://play.golang.org/p/3bXxnHOK8_

Access pointer value of a struct inside a function

I want to pass a struct object to a function & be able to access its pointer value from that function. I am not able to understand why the following is resulting in error.
func GetStructFieldPointers(u interface{}, jsonFields []string) []interface{} {
structVal := reflect.ValueOf(&u).Elem()
structType := reflect.TypeOf(u)
numberOfFields := structVal.NumField() // getting error here reflect:
// call of reflect.Value.NumField
// on interface Value
numberOfJSONFields := len(jsonFields)
res := make([]interface{}, numberOfJSONFields)
fmt.Println(jsonFields)
for fieldIndex, field := range jsonFields {
for i := 0; i < numberOfFields; i++ {
if structType.Field(i).Tag.Get("json") == field {
valueField := structVal.Field(i)
res[fieldIndex] = valueField.Addr().Interface()
}
}
}
return res
}
type User struct {
Id int `json:"id"`
Name string `json:"name"`
Address string `json:"address"`
}
user := User{}
res := GetStructFieldPointers(user, []string{"id", "name"})
To make this work, I had to make structType as a parameter like following:
func GetStructFieldPointers(u interface{}, structType reflect.Type, jsonFields []string) []interface{} {
structVal := reflect.ValueOf(u).Elem()
// structType := reflect.TypeOf(u)
numberOfFields := structVal.NumField()
numberOfJSONFields := len(jsonFields)
res := make([]interface{}, numberOfJSONFields)
fmt.Println(jsonFields)
for fieldIndex, field := range jsonFields {
for i := 0; i < numberOfFields; i++ {
if structType.Field(i).Tag.Get("json") == field {
valueField := structVal.Field(i)
res[fieldIndex] = valueField.Addr().Interface()
}
}
}
return res
}
user := User{}
res := GetStructFieldPointers(&user, reflect.TypeOf(user), []string{"id", "name"})
I like to know how to pass User{} as a parameter & use in both reflect.ValueOf & reflect.TypeOf calls.
On this line: structVal := reflect.ValueOf(&u).Elem() you're taking the address of an interface (the argument of your func) and not an address to the interface's underlying value, and then you're passing the pointer to ValueOf, so the .Elem() call returns the "elem value" to which the pointer points to, which is the interface, not struct.
If you know for a fact that the passed in value is a struct and not a pointer, all you need is this: structVal := reflect.ValueOf(u).
If a pointer was passed to your func, eg GetStructFieldPointers(&u, ... then this is what you want: structVal := reflect.ValueOf(u).Elem().
But also you can handle both cases by checking the value's kind.
rv := reflect.ValueOf(u)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if rv.Kind() == reflect.Struct {
fmt.Println(rv.NumField())
}
https://play.golang.org/p/9F9LNnwEaH
Update:
Took a better look at your code... If you want to be able to get the addresses of your struct's fields, you need to pass a pointer to the struct as the argument, or else those fields are going to be unaddressable.
https://play.golang.org/p/RaA2rau3s-

Resources