Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is reflection working with UNEXPORTED Struct and Unexported Fields?

Tags:

I expected in code to Work with struct Dish was EXPORTED as Dish. I expected the program to fail when a structure dish was unexported and not see the unexported field within it. (OK, I could see the unexported field being present in an EXPORTED STRUCTURE, but even that seems wrong).

But program still works as shown?? How can the reflection package see 'dish' if it is unexported?

--------------Program Follows---------- //Modified Example From blog: http://merbist.com/2011/06/27/golang-reflection-exampl/

package main

import (
    "fmt"
    "reflect"
)

func main() {
    // iterate through the attributes of a Data Model instance
    for name, mtype := range attributes(&dish{}) {
        fmt.Printf("Name:  %s,  Type:  %s\n", name, mtype)
    }
}

// Data Model
type dish struct {
    Id     int
    last   string
    Name   string
    Origin string
    Query  func()
}

// Example of how to use Go's reflection
// Print the attributes of a Data Model
func attributes(m interface{}) map[string]reflect.Type {
    typ := reflect.TypeOf(m)
    // if a pointer to a struct is passed, get the type of the dereferenced object
    if typ.Kind() == reflect.Ptr {
        typ = typ.Elem()
    }

    // create an attribute data structure as a map of types keyed by a string.
    attrs := make(map[string]reflect.Type)
    // Only structs are supported so return an empty result if the passed object
    // isn't a struct
    if typ.Kind() != reflect.Struct {
        fmt.Printf("%v type can't have attributes inspected\n", typ.Kind())
        return attrs
    }

    // loop through the struct's fields and set the map
    for i := 0; i < typ.NumField(); i++ {
        p := typ.Field(i)
        fmt.Println("P = ", p)
        if !p.Anonymous {
            attrs[p.Name] = p.Type
        }
    }

    return attrs
}
like image 451
Godfather Avatar asked Jun 11 '16 00:06

Godfather


1 Answers

From: https://blog.golang.org/laws-of-reflection

the field names of T are upper case (exported) because only exported fields of a struct are settable."

This easily shows and proves the concept:

fmt.Printf("can set 'last'? %v; can set 'Id'? %v",
    reflect.ValueOf(&dish{}).Elem().FieldByName("last").CanSet(),
    reflect.ValueOf(&dish{}).Elem().FieldByName("Id").CanSet(),
)

This prints: can set 'last'? false; can set 'Id'? true

On the visibility of the type (struct) name ("dish" vs "Dish") that only affects the visibility when you directly use the type at compile time. For example:

import "whatever/something"
...
v := something.someStruct{} // will give compile error
...
// this can return an instance of someStruct, which can be inspected
// with reflect just like any other struct (and that works fine because
// we haven't directly put a literal "something.someStruct" in this code
v := something.SomeFunc()
like image 171
Brad Peabody Avatar answered Sep 28 '22 03:09

Brad Peabody