re: solving: panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

1,588 views
Skip to first unread message

Alexander Mills

unread,
Feb 8, 2020, 11:01:03 AM2/8/20
to golang-nuts
I am trying to get an answer to my github gist Q:


if anyone knows if this is possible in Golang v1.13+ please lmk

Tamás Gulácsi

unread,
Feb 8, 2020, 11:18:40 AM2/8/20
to golang-nuts
Yes, I know several ways.

Alexander Mills

unread,
Feb 8, 2020, 2:42:32 PM2/8/20
to golang-nuts
it looks like this way works:

https://stackoverflow.com/a/43918797/12211419

know of any others?

Tamás Gulácsi

unread,
Feb 8, 2020, 3:07:06 PM2/8/20
to golang-nuts
Yup, that's one - get the address of the field and get that.

Another is to declare a similar (memory and type-wise) structure with exported fields,
and unsafe-type-cast it: https://play.golang.org/p/z0QG-CP_MSL

Axel Wagner

unread,
Feb 8, 2020, 7:13:31 PM2/8/20
to Tamás Gulácsi, golang-nuts
No need for unsafe:
You can't *modify* the field, but you can read it just fine. In fact, that's how fmt does it as well:
I suspect you are seeing the error you are seeing because you are either trying to modify it (calling one of the Set* methods of reflect.Value) or use reflect.Value.Interface, which I guess isn't allowed because it might enable you to call methods on that unexported field value and modifying it or something?
Either way, if you switch on the reflect.Value.Kind() and use the .String/.Int/.Bool etc., you can read the value at least.

--
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.
To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/836756d6-0654-4341-8a2e-af57ff07a231%40googlegroups.com.

Axel Wagner

unread,
Feb 8, 2020, 7:19:31 PM2/8/20
to golang-nuts
(then again, the fact that this works seems slightly concerning to me: https://play.golang.org/p/phWQ83wPQtx)

roger peppe

unread,
Feb 10, 2020, 5:47:04 AM2/10/20
to Axel Wagner, golang-nuts
On Sun, 9 Feb 2020 at 00:19, 'Axel Wagner' via golang-nuts <golan...@googlegroups.com> wrote:
(then again, the fact that this works seems slightly concerning to me: https://play.golang.org/p/phWQ83wPQtx)

Oh, that's interesting! Is this the only way that you can use reflect (without unsafe) to modify the contents of unexported fields?
I think it might be.

Axel Wagner

unread,
Feb 10, 2020, 7:15:49 AM2/10/20
to roger peppe, golang-nuts
It's reflect, so I don't feel confident in making any absolute statements (we've talked about it a bunch; I just find the implications of that API far too unwieldy to handle), but I tend to agree. You need a reference value and Bytes() seems the only typed reference value you can get out of reflect.Value without using Interface() and type-assertion. I don't think this can be fixed either - not just because of compatibility, but also because it would impede fmt.Print*.

Ian Lance Taylor

unread,
Feb 10, 2020, 10:38:52 PM2/10/20
to Axel Wagner, roger peppe, golang-nuts
On Mon, Feb 10, 2020 at 4:15 AM 'Axel Wagner' via golang-nuts
<golan...@googlegroups.com> wrote:
>
> It's reflect, so I don't feel confident in making any absolute statements (we've talked about it a bunch; I just find the implications of that API far too unwieldy to handle), but I tend to agree. You need a reference value and Bytes() seems the only typed reference value you can get out of reflect.Value without using Interface() and type-assertion. I don't think this can be fixed either - not just because of compatibility, but also because it would impede fmt.Print*.

https://golang.org/issue/27727.

Ian

> On Mon, Feb 10, 2020 at 11:46 AM roger peppe <rogp...@gmail.com> wrote:
>>
>> On Sun, 9 Feb 2020 at 00:19, 'Axel Wagner' via golang-nuts <golan...@googlegroups.com> wrote:
>>>
>>> (then again, the fact that this works seems slightly concerning to me: https://play.golang.org/p/phWQ83wPQtx)
>>
>>
>> Oh, that's interesting! Is this the only way that you can use reflect (without unsafe) to modify the contents of unexported fields?
>> I think it might be.
>>
> --
> 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.
> To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/CAEkBMfG%3Di%2BPgKBfsNPtWNZXMzQV2AAqk%3DnQuo7Oi_pabXcJQEA%40mail.gmail.com.

roger peppe

unread,
Feb 11, 2020, 8:47:48 AM2/11/20
to Ian Lance Taylor, Axel Wagner, golang-nuts
On Tue, 11 Feb 2020 at 03:38, Ian Lance Taylor <ia...@golang.org> wrote:
On Mon, Feb 10, 2020 at 4:15 AM 'Axel Wagner' via golang-nuts
<golan...@googlegroups.com> wrote:
>
> It's reflect, so I don't feel confident in making any absolute statements (we've talked about it a bunch; I just find the implications of that API far too unwieldy to handle), but I tend to agree. You need a reference value and Bytes() seems the only typed reference value you can get out of reflect.Value without using Interface() and type-assertion. I don't think this can be fixed either - not just because of compatibility, but also because it would impede fmt.Print*.

https://golang.org/issue/27727.

Ah, thanks! I'd missed that. I added a comment there FWIW.

Rohit Basu

unread,
Aug 11, 2022, 9:14:55 AM8/11/22
to golang-nuts

// A use case to avoid:: panic: reflect.Value.Interface: cannot return value obtained from unexported field or method

```
package main

import (
    "fmt"
    "reflect"
    "strings"
    "unsafe"
)

type Person1 struct {
    W3ID string
    Name string
}

type Address1 struct {
    city    string
    country string
}

type User1 struct {
    name      string
    age       int
    address   Address1
    manager   Person1
    developer Person1
    tech      Person1
}

func showDetails(load, email interface{}) {
    //fmt.Println("The values in the first argument are :")
    if reflect.ValueOf(load).Kind() == reflect.Struct {
        typ := reflect.TypeOf(load)
        value := reflect.ValueOf(load)
        value2 := reflect.New(value.Type()).Elem() // #1 For struct, not addressable create a copy With Elements.
        value2.Set(value)                          //#2 Value2 is addressable and can be set
        for i := 0; i < typ.NumField(); i++ {
            //fmt.Println(value.Field(i).Kind(), "---------")
            if value.Field(i).Kind() == reflect.Struct {
                rf := value2.Field(i)
                rf = reflect.NewAt(rf.Type(), unsafe.Pointer(rf.UnsafeAddr())).Elem()
                irf := rf.Interface()
                typrf := reflect.TypeOf(irf)
                nameP := typrf.String()
                if strings.Contains(nameP, "Person") {
                    //fmt.Println(nameP, "FOUND !!!!!!! ")
                    for j := 0; j < typrf.NumField(); j++ {
                        //fmt.Println(j)
                        re := rf.Field(j)
                        nameW := typrf.Field(j).Name
                        //fmt.Println(nameW)
                        if strings.Contains(nameW, "W3ID") {
                            //fmt.Println(nameW)
                            valueW := re.Interface()
                            fetchEmail := valueW.(string)
                            //fmt.Println(fetchEmail)
                            if fetchEmail == email {
                                fmt.Println(fetchEmail, " MATCH!!!!")
                            }
                        }
                    }
                }
                //fmt.Println(rf.Interface(), "++=====")
                showDetails(irf, email)
            } else {
                // fmt.Printf("%d.Type:%T || Value:%#v\n",
                //     (i + 1), value.Field(i), value.Field(i))

                // fmt.Println("Kind is ", value.Field(i).Kind())
            }
        }
    }
}

func main() {
    iD := "ts...@in.org.com"

    load := User1{
        name: "John Doe",
        age:  34,
        address: Address1{
            city:    "New York",
            country: "USA",
        },
        manager: Person1{
            W3ID: "jB...@in.org.com",
            Name: "Bualt",
        },
        developer: Person1{
            W3ID: "ts...@in.org.com",
            Name: "Sumi",
        },
        tech: Person1{
            W3ID: "lP...@in.org.com",
            Name: "Paul",
        },
    }

    showDetails(load, iD)
}
```
Reply all
Reply to author
Forward
0 new messages