Note that there are some explanatory texts on larger screens.

plurals
  1. POHow to pass a dynamically created struct as non-pointer object in Go
    primarykey
    data
    text
    <p>I'm trying to dynamically pass parameters to a URL route handler function. I thought it would be possible to use the reflection package to convert a map of values from the URL to the function that has one parameter that happens to be an anonymous struct. I've gotten as far as creating the struct to pass to the handler function but it ends up being a pointer to the struct. If I change the handler function's signature to expect a pointer the created struct ends up being a pointer to a pointer, I think. At any rate, here's the code (the panic follows):</p> <p>Link: <a href="http://play.golang.org/p/vt_wNY1f08" rel="nofollow">http://play.golang.org/p/vt_wNY1f08</a></p> <pre><code>package main import ( "errors" "fmt" "net/http" "reflect" "strconv" "github.com/gorilla/mux" ) func mapToStruct(obj interface{}, mapping map[string]string) error { dataStruct := reflect.Indirect(reflect.ValueOf(obj)) if dataStruct.Kind() != reflect.Struct { return errors.New("expected a pointer to a struct") } for key, data := range mapping { structField := dataStruct.FieldByName(key) if !structField.CanSet() { fmt.Println("Can't set") continue } var v interface{} switch structField.Type().Kind() { case reflect.Slice: v = data case reflect.String: v = string(data) case reflect.Bool: v = string(data) == "1" case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32: x, err := strconv.Atoi(string(data)) if err != nil { return errors.New("arg " + key + " as int: " + err.Error()) } v = x case reflect.Int64: x, err := strconv.ParseInt(string(data), 10, 64) if err != nil { return errors.New("arg " + key + " as int: " + err.Error()) } v = x case reflect.Float32, reflect.Float64: x, err := strconv.ParseFloat(string(data), 64) if err != nil { return errors.New("arg " + key + " as float64: " + err.Error()) } v = x case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: x, err := strconv.ParseUint(string(data), 10, 64) if err != nil { return errors.New("arg " + key + " as int: " + err.Error()) } v = x default: return errors.New("unsupported type in Scan: " + reflect.TypeOf(v).String()) } structField.Set(reflect.ValueOf(v)) } return nil } type RouteHandler struct { Handler interface{} } func (h RouteHandler) ServeHTTP(w http.ResponseWriter, req *http.Request) { t := reflect.TypeOf(h.Handler) handlerArgs := reflect.New(t.In(0)).Interface() if err := mapToStruct(handlerArgs, mux.Vars(req)); err != nil { panic(fmt.Sprintf("Error converting params")) } f := reflect.ValueOf(h.Handler) args := []reflect.Value{reflect.ValueOf(handlerArgs)} f.Call(args) fmt.Fprint(w, "Hello World") } type App struct { Router mux.Router } func (app *App) Run(bind string, port int) { bind_to := fmt.Sprintf("%s:%d", bind, port) http.Handle("/", &amp;app.Router) http.ListenAndServe(bind_to, &amp;app.Router) } func (app *App) Route(pat string, h interface{}) { app.Router.Handle(pat, RouteHandler{Handler:h}) } func home(args struct{Category string}) { fmt.Println("home", args.Category) } func main() { app := &amp;App{} app.Route("/products/{Category}", home) app.Run("0.0.0.0", 8080) } </code></pre> <p>Panic:</p> <pre><code>2013/03/28 18:48:43 http: panic serving 127.0.0.1:51204: reflect: Call using *struct { Category string } as type struct { Category string } /usr/local/Cellar/go/1.0.3/src/pkg/net/http/server.go:589 (0x3fb66) _func_004: buf.Write(debug.Stack()) /usr/local/Cellar/go/1.0.3/src/pkg/runtime/proc.c:1443 (0x11cdb) panic: reflect·call(d-&gt;fn, d-&gt;args, d-&gt;siz); /usr/local/Cellar/go/1.0.3/src/pkg/reflect/value.go:428 (0x484ba) Value.call: panic("reflect: " + method + " using " + xt.String() + " as type " + targ.String()) /usr/local/Cellar/go/1.0.3/src/pkg/reflect/value.go:334 (0x47c3a) Value.Call: return v.call("Call", in) /Users/matt/Workspaces/Go/src/pants/pants.go:86 (0x2f36) RouteHandler.ServeHTTP: f.Call(args) /Users/matt/Workspaces/Go/src/pants/pants.go:1 (0x347c) (*RouteHandler).ServeHTTP: package main /Users/matt/Workspaces/Go/src/github.com/gorilla/mux/mux.go:86 (0x5a699) com/gorilla/mux.(*Router).ServeHTTP: handler.ServeHTTP(w, req) /usr/local/Cellar/go/1.0.3/src/pkg/net/http/server.go:669 (0x337b6) (*conn).serve: handler.ServeHTTP(w, w.req) /usr/local/Cellar/go/1.0.3/src/pkg/runtime/proc.c:271 (0xfde1) goexit: runtime·goexit(void) </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload