How to set array value to a field in golang using reflect? - reflection

I have a Struct with following fields
type Config struct {
Address[]string
Name string
}
I am reading the values for this Config from a file in JSON format
{
"Address": ["xx.xx.xx.xx","xx.xx.xx.xx"],
"Name":"Name"
}
I have used Reflect to identify the type and set its value to Config.I am able to set the value of Name field using
func (v Value) SetString(x string) which is an inbuilt method in reflect. Is there a way to set []string values directly to a field? Please help.

You can use the json package for that (it uses reflect internally):
package main
import (
"encoding/json"
"fmt"
)
type Config struct {
Address []string
Name string
}
var someJson = []byte(`{
"Address": ["xx.xx.xx.xx","xx.xx.xx.xx"],
"Name":"Name"
}`)
func main() {
var config Config
err := json.Unmarshal(someJson, &config)
if err != nil {
fmt.Println("error: ", err)
}
fmt.Printf("%v", config)
}

Related

Pass struct interface to sqlite exec

In Go, I'm trying to pass an interface{} to the statement.Exec() function from go-sqlite3. I'm sure this is a solved problem, but I cannot figure it out.
Basically I have a struct with the row data which I want to pass to a function that will insert it to a sqlite db. The thing is I want to be able to programmatically control what goes into the statement.Exec() function
Here is an excerpt:
type hostRows struct {
domain string
}
type clientRows struct {
name string
}
func main() {
...
data := hostRows{domain: "dom.com"}
insertRow(sqliteDatabase, data)
data2 := clientRows{name: "bob"}
insertRow(sqliteDatabase, data2)
...
}
func insertRow(db *sql.DB, row interface{}) {
insertSQL := "INSERT INTO table(col) VALUES (?)"
statement, _ := db.Prepare(insertSQL)
statement.Exec(row) // here's the issue, how can I extract the element in the interface to pass it to the function for Exec to understand
}
I know that in this example, I could hard code the row type to the struct and type statement.Exec(row.(hostRows).domain), but now the code will break to when the client struct is passed.
here is the deceleration for the Exec function
func (s *Stmt) Exec(args ...interface{}) (Result, error)
I've tried playing with reflect but it hasn't worked for me so far.
My only solution for the moment is using a switch condition that could check and prepare the right command for Exec, but this is less than dodgy.
type hostRows struct {
domain string
}
type clientRows struct {
name string
}
func main() {
...
data := hostRows{domain: "dom.com"}
insertRow(sqliteDatabase, 1, data)
data2 := clientRows{name: "bob"}
insertRow(sqliteDatabase, 2, data2)
...
}
func insertRow(db *sql.DB, i int, row interface{}) {
insertSQL := "INSERT INTO table(col) VALUES (?)"
statement, _ := db.Prepare(insertSQL)
// This basically could be a working solution, but I'm sure there is a better one
switch i {
case 1:
data := row.(hostRows)
statement.Exec(data.domain)
case 2:
data := row.(clientRows)
statement.Exec(data.name)
}
}
edit: corrected the INSERT statement ; forget the columns. corrected statement.Exec(row.domain) to statement.Exec(row.(hostRows).domain)
edit2: added second example
Remember that in order for reflect.Interface() to work, you must export the fields. To achieve what you want using reflection, you could try something like this:
type hostRows struct {
//Should export field to read it using reflect.Value.Interface()
Domain string
}
type clientRows struct {
//Should export field to read it using reflect.Value.Interface()
Name string
}
func insertRow(db *sql.DB, i int, row interface{}) {
rv := reflect.ValueOf(row)
var args []interface{}
for i := 0; i < rv.NumField(); i++ {
args = append(args, rv.Field(i).Interface())
}
db.Exec("Insert Satement...", args...)
}

Passing structs to functions across packages

In an attempt to become more familiar with go, I am trying to refactor some code which is already working fine.
The original code has three structs:
type ConfigGroup struct {
Interval int
Tprefix string
Target []string
}
type ConfigDefaults struct {
Interval int
Sprefix string
}
type Config struct {
Group map[string]*ConfigGroup
Defaults ConfigDefaults
}
These structs get passed to a function like so:
func runpinger(clientStatsd statsd.Statter, defaults *ConfigDefaults, group *ConfigGroup) {
// some stuff here
}
Now, I've reworked the config (which uses gocfg) to use hcl instead, which seems to provide a cleaner config syntax.
I've moved the config parser into a package, config, with structs that look like this:
type Config struct {
Interval int `hcl:"interval"`
Prefix string `hcl:"prefix"`
Groups []TargetGroups `hcl:"target_group"`
}
type TargetGroups struct {
Name string `hcl:",key"`
Prefix string `hcl:"prefix"`
Interval int `hcl:"interval"`
Targets []Targets `hcl:"target"`
}
type Targets struct {
Address string `hcl:"address"`
Label string `hcl:"label"`
}
and then a function in config package that looks like this:
func Parse(ConfigFile string) (*Config, error) {
result := &Config{}
var errors *multierror.Error
config, err := ioutil.ReadFile(ConfigFile)
if err != nil {
return nil, err
}
hclParseTree, err := hcl.Parse(string(config))
if err != nil {
return nil, err
}
if err := hcl.DecodeObject(&result, hclParseTree); err != nil {
return nil, err
}
return result, errors.ErrorOrNil()
}
Now, in my main package I'd like to pass these structs to the function again. How can I do this across packages?
I tried:
func(runpinger config *config.Config) {
// here
}
But that didn't seem to work. Ideally, I'd like to just pass a pointer to the "sub-struct" (ie the TargetGroups struct) as well, although I'm not sure if that's possible.
You should be able to pass the structs to the main package, just check that you put import "path/to/config" at the top of your file.
The path has to be the full path to your package from your $GOPATH/src/ directory

Initialize a nil pointer struct in method

I have a struct called Article which has a field called Image. Per default Image has value nil. As Image should be only persisted as Image.Id to database I use the bson.BSONGetter, bson.BSONSetter and json.Marshaler interfaces to fake this behavior.
However internally it is possible to use Image as an io.ReadWriteCloser if I load a file onto this with some other helper.
package main
import (
"io"
"fmt"
"gopkg.in/mgo.v2"
)
type Article struct {
Name string
Image *Image
}
type Image struct {
Id interface{}
io.ReadWriteCloser
}
func (i *Image) SetBSON(r bson.Raw) error {
i = &Image{}
return r.Marshal(i.Id)
}
func (i *Image) GetBSON() (interface{}, error) {
return i.Id
}
func (i *Image) MarshalJSON() ([]byte, error) {
return json.Marshal(i.Id)
}
Playground
The problem with this approach now is that it is not possible to initialize Image in Image.SetBSON as Image is nil.
The receiver is passed by value, including the pointer receiver: it is a copy, and changing its value doesn't change the initial pointer receiver on which the method is called.
See "Why are receivers pass by value in Go?".
A function Setup returning a new *Foo would work better: play.golang.org
func SetUp() *Foo {
return &Foo{"Hello World"}
}
func main() {
var f *Foo
f = SetUp()
}
Output:
Foo: <nil>
Foo: &{Bar:Hello World}
twotwotwo points to a better convention in the comments, which is to make a package function foo.New(), as in sha512.New().
But here, your Setup() function might do more than just creating a *Foo.
bson.Unmarshal creates a pointer to an Image value when it comes across it in the bson data. So once we enter SetBSON i is already a valid pointer to an Image struct. That means that there is no reason for you to allocate the Image.
package main
import (
"fmt"
"io"
"gopkg.in/mgo.v2/bson"
)
type Article struct {
Name string
Image *Image `bson:"image,omitempty"`
}
type Image struct {
Id interface{}
AlsoIgnored string
io.ReadWriteCloser
}
func (i *Image) SetBSON(r bson.Raw) error {
err := r.Unmarshal(&i.Id)
return err
}
func (i Image) GetBSON() (interface{}, error) {
return i.Id, nil
}
func main() {
backAndForth(Article{
Name: "It's all fun and games until someone pokes an eye out",
Image: &Image{
Id: "123",
AlsoIgnored: "test",
},
})
backAndForth(Article{Name: "No img attached"})
}
func backAndForth(a Article) {
bsonData, err := bson.Marshal(a)
if err != nil {
panic(err)
}
fmt.Printf("bson form: '%s'\n", string(bsonData))
article := &Article{}
err = bson.Unmarshal(bsonData, article)
if err != nil {
panic(err)
}
fmt.Printf("go form : %#v - %v\n", article, article.Image)
}
http://play.golang.org/p/_wb6_8Pe-3
Output is:
bson form: 'Tname6It's all fun and games until someone pokes an eye outimage123'
go form : &main.Article{Name:"It's all fun and games until someone pokes an eye out", Image:(*main.Image)(0x20826c4b0)} - &{123 <nil>}
bson form: 'nameNo img attached'
go form : &main.Article{Name:"No img attached", Image:(*main.Image)(nil)} - <nil>

Pass by reference nested structures through reflection

type Client struct {
Id int
Age int
PrimaryContact Contact
Name string
}
type Contact struct {
Id int
ClientId int
IsPrimary bool
Email string
}
The above is a sample code; what I am trying to achieve is the following:
- loop through all Client struct fields using reflection
- for each "primitive" field set a default value using reflection
- for each struct field use recursion to apply the above steps
The issue is that when PrimaryContact field is introspected and when I am trying to set a value for any of its fields I end up with the following panic:
reflect.Value.Set using unaddressable value
The reason if I am not mistaken is that PrimaryContact is passed by value and not by reference so when I would call Set method on any of its fields it would change fields values on the copy and not on the actual argument. How can I overcome this issue? How I could pass PrimaryContact field to my method by reference using reflection?
I saw it as a fun exercise to practice reflection.
Two pointers though:
In order to set field values of a struct, you must pass it as a pointer
To get the pointer value of a struct field, use Value.Addr()
Working solution:
package main
import (
"fmt"
"reflect"
"errors"
)
type Client struct {
Id int
Age int
PrimaryContact Contact
Name string
}
type Contact struct {
Id int
ClientId int
IsPrimary bool
Email string
}
func SetDefault(s interface{}) error {
return setDefaultValue(reflect.ValueOf(s))
}
func setDefaultValue(v reflect.Value) error {
if v.Kind() != reflect.Ptr {
return errors.New("Not a pointer value")
}
v = reflect.Indirect(v)
switch v.Kind() {
case reflect.Int:
v.SetInt(42)
case reflect.String:
v.SetString("Foo")
case reflect.Bool:
v.SetBool(true)
case reflect.Struct:
// Iterate over the struct fields
for i := 0; i < v.NumField(); i++ {
err := setDefaultValue(v.Field(i).Addr())
if err != nil {
return err
}
}
default:
return errors.New("Unsupported kind: " + v.Kind().String())
}
return nil
}
func main() {
a := Client{}
err := SetDefault(&a)
if err != nil {
fmt.Println("Error: ", err)
} else {
fmt.Printf("%+v\n", a)
}
}
Output:
{Id:42 Age:42 PrimaryContact:{Id:42 ClientId:42 IsPrimary:true Email:Foo} Name:Foo}
Playground: http://play.golang.org/p/-Mpnb7o4vl
I think you just need to use value.Addr(), which gives you a reference to the Contact. Full example is here.
func main() {
x := Client{PrimaryContact:Contact{}}
v := reflect.ValueOf(&x)
fmt.Println("v type:", v.Type(), ", kind:", v.Kind())
f := v.Elem().FieldByName("PrimaryContact")
fmt.Println("f type:", f.Type(), ", kind:", f.Kind())
p := f.Addr()
fmt.Println("p type:", p.Type(), ", kind:", p.Kind())
p.Elem().FieldByName("Id").SetInt(1)
fmt.Println("Contact Id:", x.PrimaryContact.Id)
}`
Output:
v type: *main.Client , kind: ptr
f type: main.Contact , kind: struct
p type: *main.Contact , kind: ptr
Contact Id: 1

function for converting a struct to map in Golang

I want to convert a struct to map in Golang. It would also be nice if I could use the JSON tags as keys in the created map (otherwise defaulting to field name).
Edit Dec 14, 2020
Since structs repo was archived, you can use mapstructure instead.
Edit TL;DR version, Jun 15, 2015
If you want the fast solution for converting a structure to map, see the accepted answer, upvote it and use that package.
Happy coding! :)
Original Post
So far I have this function, I am using the reflect package but I don't understand well how to use the package, please bear with me.
func ConvertToMap(model interface{}) bson.M {
ret := bson.M{}
modelReflect := reflect.ValueOf(model)
if modelReflect.Kind() == reflect.Ptr {
modelReflect = modelReflect.Elem()
}
modelRefType := modelReflect.Type()
fieldsCount := modelReflect.NumField()
var fieldData interface{}
for i := 0; i < fieldsCount; i++ {
field := modelReflect.Field(i)
switch field.Kind() {
case reflect.Struct:
fallthrough
case reflect.Ptr:
fieldData = ConvertToMap(field.Interface())
default:
fieldData = field.Interface()
}
ret[modelRefType.Field(i).Name] = fieldData
}
return ret
}
Also I looked at JSON package source code, because it should contain my needed implementation (or parts of it) but don't understand too much.
I also had need for something like this. I was using an internal package which was converting a struct to a map. I decided to open source it with other struct based high level functions. Have a look:
https://github.com/fatih/structs
It has support for:
Convert struct to a map
Extract the fields of a struct to a []string
Extract the values of a struct to a []values
Check if a struct is initialized or not
Check if a passed interface is a struct or a pointer to struct
You can see some examples here: http://godoc.org/github.com/fatih/structs#pkg-examples
For example converting a struct to a map is a simple:
type Server struct {
Name string
ID int32
Enabled bool
}
s := &Server{
Name: "gopher",
ID: 123456,
Enabled: true,
}
// => {"Name":"gopher", "ID":123456, "Enabled":true}
m := structs.Map(s)
The structs package has support for anonymous (embedded) fields and nested structs. The package provides to filter certain fields via field tags.
From struct to map[string]interface{}
package main
import (
"fmt"
"encoding/json"
)
type MyData struct {
One int
Two string
Three int
}
func main() {
in := &MyData{One: 1, Two: "second"}
var inInterface map[string]interface{}
inrec, _ := json.Marshal(in)
json.Unmarshal(inrec, &inInterface)
// iterate through inrecs
for field, val := range inInterface {
fmt.Println("KV Pair: ", field, val)
}
}
go playground here
Here is a function I've written in the past to convert a struct to a map, using tags as keys
// ToMap converts a struct to a map using the struct's tags.
//
// ToMap uses tags on struct fields to decide which fields to add to the
// returned map.
func ToMap(in interface{}, tag string) (map[string]interface{}, error){
out := make(map[string]interface{})
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
// we only accept structs
if v.Kind() != reflect.Struct {
return nil, fmt.Errorf("ToMap only accepts structs; got %T", v)
}
typ := v.Type()
for i := 0; i < v.NumField(); i++ {
// gets us a StructField
fi := typ.Field(i)
if tagv := fi.Tag.Get(tag); tagv != "" {
// set key of map to value in struct field
out[tagv] = v.Field(i).Interface()
}
}
return out, nil
}
Runnable example here.
Note, if you have multiple fields with the same tag value, then you will obviously not be able to store them all within a map. It might be prudent to return an error if that happens.
I like the importable package for the accepted answer, but it does not translate my json aliases. Most of my projects have a helper function/class that I import.
Here is a function that solves my specific problem.
// Converts a struct to a map while maintaining the json alias as keys
func StructToMap(obj interface{}) (newMap map[string]interface{}, err error) {
data, err := json.Marshal(obj) // Convert to a json string
if err != nil {
return
}
err = json.Unmarshal(data, &newMap) // Convert to a map
return
}
And in the main, this is how it would be called...
package main
import (
"fmt"
"encoding/json"
"github.com/fatih/structs"
)
type MyStructObject struct {
Email string `json:"email_address"`
}
func main() {
obj := &MyStructObject{Email: "test#test.com"}
// My solution
fmt.Println(StructToMap(obj)) // prints {"email_address": "test#test.com"}
// The currently accepted solution
fmt.Println(structs.Map(obj)) // prints {"Email": "test#test.com"}
}
package main
import (
"fmt"
"reflect"
)
type bill struct {
N1 int
N2 string
n3 string
}
func main() {
a := bill{4, "dhfthf", "fdgdf"}
v := reflect.ValueOf(a)
values := make(map[string]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
if v.Field(i).CanInterface() {
values[v.Type().Field(i).Name] = v.Field(i).Interface()
} else {
fmt.Printf("sorry you have a unexported field (lower case) value you are trying to sneak past. I will not allow it: %v\n", v.Type().Field(i).Name)
}
}
fmt.Println(values)
passObject(&values)
}
func passObject(v1 *map[string]interface{}) {
fmt.Println("yoyo")
}
I'm a bit late but I needed this kind of feature so I wrote this. Can resolve nested structs. By default, uses field names but can also use custom tags. A side effect is that if you set the tagTitle const to json, you could use the json tags you already have.
package main
import (
"fmt"
"reflect"
)
func StructToMap(val interface{}) map[string]interface{} {
//The name of the tag you will use for fields of struct
const tagTitle = "kelvin"
var data map[string]interface{} = make(map[string]interface{})
varType := reflect.TypeOf(val)
if varType.Kind() != reflect.Struct {
// Provided value is not an interface, do what you will with that here
fmt.Println("Not a struct")
return nil
}
value := reflect.ValueOf(val)
for i := 0; i < varType.NumField(); i++ {
if !value.Field(i).CanInterface() {
//Skip unexported fields
continue
}
tag, ok := varType.Field(i).Tag.Lookup(tagTitle)
var fieldName string
if ok && len(tag) > 0 {
fieldName = tag
} else {
fieldName = varType.Field(i).Name
}
if varType.Field(i).Type.Kind() != reflect.Struct {
data[fieldName] = value.Field(i).Interface()
} else {
data[fieldName] = StructToMap(value.Field(i).Interface())
}
}
return data
}
map := Structpb.AsMap()
// map is the map[string]interface{}

Resources