Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is go reflect CanInterface false?

Tags:

reflection

go

As per this playground example (https://play.golang.org/p/Jr64yE4zSpQ), and the implementation of CanInterface in reflect/value.go, it looks like CanInterface is false only for private fields?

What are other scenarios when CanInterface is false?

Playground example:

num := 6
meta := reflect.ValueOf(num)
fmt.Println("canInterface:", meta.CanInterface() == true)

meta = reflect.ValueOf(&num)
fmt.Println("canInterface:", meta.CanInterface() == true)

foo := Foo{}
meta = reflect.ValueOf(&foo)
fmt.Println("canInterface:", meta.CanInterface() == true)
meta = meta.Elem()
fmt.Println("canInterface:", meta.CanInterface() == true)
publicField := meta.FieldByName("Number")
privateField := meta.FieldByName("privateNumber")
fmt.Println(
    "canInterface:", 
    publicField.CanInterface() == true,
    // Woah, as per the implementation (reflect/value.go) 
    // this is the only time it can be false
    privateField.CanInterface() != true)

var fooPtr *Foo
var ptr anInterface = fooPtr
meta = reflect.ValueOf(ptr)
fmt.Println("canInterface:", meta.CanInterface() == true)

meta = reflect.ValueOf(&foo)
meta = meta.Elem() // ptr to actual value
publicField = meta.FieldByName("Number")
ptrToField := publicField.Addr()
fmt.Println("canInterface:", ptrToField.CanInterface() == true)

reflect/value.go

func (v Value) CanInterface() bool {
if v.flag == 0 {
    panic(&ValueError{"reflect.Value.CanInterface", Invalid})
}
// I think "flagRO" means read-only?
return v.flag&flagRO == 0
}
like image 881
U Avalos Avatar asked Apr 08 '26 14:04

U Avalos


1 Answers

If you dive into the source code for CanInterface, you can see this line:

return v.flag&flagRO == 0

And a bit below it, this block of code from the function valueInterface:

if safe && v.flag&flagRO != 0 {
    // Do not allow access to unexported values via Interface,
    // because they might be pointers that should not be
    // writable or methods or function that should not be callable.
    panic("reflect.Value.Interface: cannot return value obtained from unexported field or method")
}

Since v.flag&flagRO != 0 is equivalent to !CanInterface, we can conclude from the comment below it that CanInterface is false when the reflect.Value is an unexported struct field or method.

like image 182
Zippo Avatar answered Apr 12 '26 14:04

Zippo