package main import ( "fmt" "reflect" ) // to be used in association with the golang sql package, rows.Scan() // pass in any struct object/object slice you like and get appropriate results using reflection // restriction: the sql query result's columns length must match the struct object fields length (len(rows.Columns(), fix your query) // feel free to use, share, modify, expand, w/e. no license agreement // annotations left, primarily for me to learn more about golang, reflection and data types as such // this example pulls 'sidebar' items into a slice for furhter usage (json marshalling) // doesn't claim to be idiomatic or best practice. use at your own risk! type ( navItem struct { ID int Name string } navItemList struct { NvL []navItem } dbWorker struct { queryObj interface{} queryObjL interface{} } ) func (dW *dbWorker) AddNavItem() { rSPtr := ptr(reflect.ValueOf(dW.queryObjL)) rVPtr := ptr(reflect.ValueOf(dW.queryObj)) /* println(rSPtr.String(), rSPtr.Elem().String(), rSPtr.Elem().Elem().String(), rSPtr.Elem().Elem().CanSet()) <**main.navItemList Value> <*main.navItemList Value> true */ ev := rSPtr.Elem().Elem().Field(0) // may be a subject to change due dynamic field allocation demand /* println(ev.String(), ev.Type().String(), ev.CanSet()) <[]main.navItem Value> []main.navItem true */ ev.Set(reflect.Append(ev, rVPtr.Elem().Elem())) } func (dW *dbWorker) changeValue(rv reflect.Value, cols []interface{}) { // rows.Scan(): due to interface{} being a pointer to type of v, dereference properly for i, v := range cols { switch v.(type) { case int: // *int rv.Field(i).SetInt(int64(v.(int))) // rv.Field(i).SetInt(int64(*(v.(*int)))) case string: // *string rv.Field(i).SetString(v.(string)) // rv.Field(i).SetString(*(v.(*string))) case bool: // *bool rv.Field(i).SetBool(v.(bool)) // rv.Field(i).SetBool(*(v.(*bool))) default: fmt.Printf("Type assert not defined. Type is %T", v) } } } func (dW *dbWorker) rowsNextIteration(newint int, newstr string) { rv := ptr(reflect.ValueOf(dW.queryObj)) /* println(rv.String(), rv.Elem().String(), rv.Elem().Elem().String(), rv.Elem().Elem().CanSet()) <**main.navItem Value> <*main.navItem Value> true */ em := rv.Elem().Elem() num := em.NumField() cols := make([]interface{}, num) for i := 0; i < num; i++ { field := em.Field(i) cols[i] = field.Interface() /* switch cols[i].(type) { case int: println("ID-A", cols[i].(int)) cols[i] = 3 field.SetInt(int64(cols[i].(int))) case string: println("NAME-A", cols[i].(string)) cols[i] = "str2" field.SetString(cols[i].(string)) default: fmt.Printf("Type assert not defined. Type is %T", v) } */ } /* println("ID-A", cols[0].(int)) println("NAME-A", cols[1].(string)) */ cols[0] = newint cols[1] = newstr dW.changeValue(em, cols) dW.AddNavItem() } func main() { ni := &navItem{} ni.ID = 2 ni.Name = "str1" nis := &navItemList{} myWorker := &dbWorker{} println("NvL-A", len(nis.NvL)) /* nis.NvL = append(nis.NvL, *ni) println("NvL-B", len(nis.NvL)) */ myWorker.queryObjL = nis myWorker.queryObj = ni myWorker.rowsNextIteration(3, "str2") myWorker.rowsNextIteration(4, "str3") myWorker.rowsNextIteration(5, "str4") /* myWorker.AddNavItem() println("ID-B", ni.ID) println("NAME-B", ni.Name) */ println("NvL-B", len(nis.NvL)) printSlice(*nis) } func printSlice(niL navItemList) { for k, v := range niL.NvL { println("NavItems", "key", k, "id", v.ID, "name", v.Name) } } // credits to https://github.com/a8m/reflect-examples // ptr wraps the given value with pointer: V => *V, *V => **V, etc. func ptr(v reflect.Value) reflect.Value { pt := reflect.PtrTo(v.Type()) // create a *T type. pv := reflect.New(pt.Elem()) // create a reflect.Value of type *T. pv.Elem().Set(v) // sets pv to point to underlying value of v. return pv }