How to access a map's nil key's value using reflection?

892 views
Skip to first unread message

gi...@iki.fi

unread,
Jan 7, 2015, 9:27:25 AM1/7/15
to golan...@googlegroups.com

For a map that has a nil key (and a value associated with it, of course):

mapp := map[interface{}]interface{}{
    nil: "a",
}

Accessing it’s nil key directly works:

fmt.Println("key[nil]:", mapp[nil])

But using reflection it doesn’t - how to do this?

rmapp := reflect.ValueOf(mapp)
rkey := reflect.ValueOf(interface{}(nil))
rval := rmapp.MapIndex(rmapp.MapIndex(rkey))  // panic: runtime error: invalid memory address or nil pointer dereference
fmt.Println("key[nil]:", rval)

Non-working code here:
https://play.golang.org/p/sCPpmpOUJw

Ian Lance Taylor

unread,
Jan 7, 2015, 9:56:47 AM1/7/15
to gi...@iki.fi, golang-nuts
I think the panic with a runtime error is a bug in the reflect
package. It should panic with some reflect error instead. Please
open an issue for this (http://golang.org/issue/new). Thanks.

In general you can't directly use an interface type with ValueOf.
This is because ValueOf takes an interface type itself, and the
original interface type is lost. You can make your program work by
using a pointer and a dereference.

empty := interface{}(nil)
rkey := reflect.ValueOf(&empty).Elem()

Ian

roger peppe

unread,
Jan 7, 2015, 12:01:35 PM1/7/15
to Ian Lance Taylor, gi...@iki.fi, golang-nuts
I agree that the panic doesn't produce a great error message,
but other than that, the behaviour of the reflect package is
correct as documented AFAICS.

The unexpected thing is that the semantics of MapIndex are not what
you might expect. In Go, indexing a map with a non-existent key
returns a value with the same type as the map elements, but MapIndex
does not behave that way - it returns a zero (invalid) value when the
element does not exist. I presume that's to avoid the need for MapIndex
to return two values.

To get the usual semantics, you'd need something like:

   func MapIndex(v, key reflect.Value) (reflect.Value, bool) { 
        elem := v.MapIndex(key)
        if elem.IsValid() {
             return elem, true
        }
        return reflect.Zero(v.Type().Elem()), false
    }

Note also that reflect.ValueOf(nil) does not produce a valid Value
with type interface{}. You'd need something like reflect.Zero(interfaceType) where
interfaceType = reflect.TypeOf((*interface{})(nil)).Elem().

Here's the example changed to demonstrate map index with a nil interface{} value:


Here's some code demonstrating that MapIndex returns an invalid value
for non-existent elements (as documented in the refect docs):


  cheers,
    rog.


--
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/d/optout.

gi...@iki.fi

unread,
Jan 7, 2015, 12:26:21 PM1/7/15
to roger peppe, Ian Lance Taylor, golang-nuts
Thank you both. The solution materialized for accessing the nil-key of a map by:

    refmap.MapIndex(reflect.Zero(refmap.Type().Key()))
Reply all
Reply to author
Forward
0 new messages