Re: Using reflect to determine type of function argument

1,015 views
Skip to first unread message

Andrew Gallant

unread,
May 15, 2013, 10:25:39 PM5/15/13
to golang-nuts
http://play.golang.org/p/41MuXxwkAS

On May 15, 5:15 pm, niklas.v...@gmail.com wrote:
> Hello gophers,
>
> I recently started learning Go and wanted to write a small
> WebSocket-Framework. I finished a basic version
> of the framework calling functions associated with events and delivering
> the sent data as interface{}.
>
> To illustrate, what I mean, this is the current API design:
>
> func echo(conn *Connection, data *map[string]interface{}) {
> fmt.Println(data["test"].(string)) // example data access
> conn.Emit("echoSuccess", data)
>
> }
>
> func main() {
>
> myrouter := NewRouter()
> myrouter.On("echo", echo)
>
> http.Handle("/", http.FileServer(http.Dir("./public")))
> http.Handle("/ws", myrouter.Handler())
>
> if err := http.ListenAndServe(*address, nil); err != nil {
> log.Fatal("ListenAndServe:", err)
>
> }
> }
>
> On the client-side I can then simply emit the echo event and send data
> along with it.
>
> What I dislike about this approach is how the data in the echo function is
> handled. Since
> I am using JSON I could also pass a json.RawMessage to the echo function
> instead of a
> map[string]interface{}, but unmarshalling it for every type of event is
> also a very repetitive
> approach. Although I could pass in then struct and access it more properly.
>
> Provisional nice API design:
> type EchoData struct {
> msg string
>
> }
>
> func echo(conn *Connection, data *EchoData) {
> fmt.Println(data.msg) // example data access
> conn.Emit("echoSuccess", data)
>
> }
>
> So the quesion is basically is there a way to determine the argument types
> of a function using reflection?
> I would then simply save the type information and try to unmarshall the
> received data accordingly.
>
> Thanks in advance,
> Niklas
Message has been deleted
Message has been deleted

Andrew Gallant

unread,
May 16, 2013, 12:39:21 PM5/16/13
to golan...@googlegroups.com, nikla...@gmail.com
Remember, `reflect.New(TYPE)` is equivalent to `new(TYPE)`. So it returns a pointer to `TYPE`. e.g., http://play.golang.org/p/SJ6TZ92CtN

So if your `reflect.New` call is a pointer to TYPE but the function expects just TYPE, then you'll probably need a call to `Elem` in there somewhere.

N.B. I didn't look too closely---in a rush. I can help more if that doesn't work.

On Thursday, May 16, 2013 9:36:42 AM UTC-4, nikla...@gmail.com wrote:
The On method of Router is now implemented as follows:

func (router *Router) On(name string, cb interface{}) {

cbValue := reflect.ValueOf(cb)

cbDataType := reflect.TypeOf(cb).In(1)

pre := func(conn *Connection, data *json.RawMessage) {
decoded := reflect.New(cbDataType)

err := json.Unmarshal(*data, &decoded)
if err == nil {
args := []reflect.Value{reflect.ValueOf(conn), decoded}
cbValue.Call(args)
} else {
fmt.Println("[JSON-FORWARD]", data, err) // TODO: Proper debug output!
}
}
router.callbacks[name] = pre
}

The problem now is if I send data the program panics:
2013/05/16 14:28:54 http: panic serving 127.0.0.1:58692: reflect: Call using **main.ChatMessage as type *main.ChatMessage

I am struggling to figure out how to get rid of this problem though...

Thanks for the great help so far,
Niklas

Dan Kortschak

unread,
May 16, 2013, 4:26:46 PM5/16/13
to nikla...@gmail.com, golan...@googlegroups.com, nikla...@gmail.com
encoding/json depends on reflect, so fields must be exported, and you want to decode in the Go type, not a reflect type representing it.

http://play.golang.org/p/vLVDDD74YG

On 17/05/2013, at 5:42 AM, "nikla...@gmail.com" <nikla...@gmail.com> wrote:

I narrowed down the problem in this snippet, that successfully compiles and runs, but the unmarshalling seems to be the problem,
since the structs msg is empty:



On Thursday, 16 May 2013 14:36:42 UTC+1, nikla...@gmail.com wrote:
The On method of Router is now implemented as follows:

func (router *Router) On(name string, cb interface{}) {

cbValue := reflect.ValueOf(cb)

cbDataType := reflect.TypeOf(cb).In(1)

pre := func(conn *Connection, data *json.RawMessage) {
decoded := reflect.New(cbDataType)

err := json.Unmarshal(*data, &decoded)
if err == nil {
args := []reflect.Value{reflect.ValueOf(conn), decoded}
cbValue.Call(args)
} else {
fmt.Println("[JSON-FORWARD]", data, err) // TODO: Proper debug output!
}
}
router.callbacks[name] = pre
}

The problem now is if I send data the program panics:
2013/05/16 14:28:54 http: panic serving 127.0.0.1:58692: reflect: Call using **main.ChatMessage as type *main.ChatMessage

I am struggling to figure out how to get rid of this problem though...

Thanks for the great help so far,
Niklas



On Thursday, 16 May 2013 03:25:39 UTC+1, Andrew Gallant wrote:

--
You received this message because you are subscribed to the Google Groups "golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 
Reply all
Reply to author
Forward
0 new messages