Why is reflection working with UNEXPORTED Struct and Unexported Fields? - go

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
}

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()

Related

Returning a pointer to a struct from a function in Go

I have two public structs that contain different data, and a private intermediate struct containing either of the two public structs. I also have a function that unmarshalls the intermediate struct, determines which public struct it contains, and returns one of the two public structs.
The problem I'm facing is the return value of the last function. At it's simplest I thought I could return *struct{} but I keep getting a type mismatch in my IDE.
I apologize for posting more code than is probably necessary, but I'm trying to make it as close as possible to the code I'm working on.
package main
import (
"encoding/json"
"errors"
)
// These vars are some errors I'll use in the functions later on
var (
errInvalidBase64 = errors.New("invalid base64")
errInvalidStructType = errors.New("invalid struct type")
)
// Struct1 public struct
type Struct1 struct {
FName string `json:"first-name"`
LName string `json:"last-name"`
}
// Struct2 public struct
type Struct2 struct {
Date string `json:"date"`
Items []int `json:"items"`
}
// intermediateStruct private struct
// The Type field indicates which kind of struct Data contains (Struct1 or Struct2)
// The Data field contains either Struct1 or Struct2 which was previously marshalled into JSON
type intermediateStruct struct {
Type structType
Data []byte
}
// The following type and const are my understanding of an enum in Go
// structType is a private type for the type of struct intermediateStruct contains
type structType int
// These public constants are just to keep my hands out of providing values for the different struct types
const (
StructType1 structType = iota
StructType2
)
// unmarshalStruct1 unmarshalls JSON []byte into a new Struct1 and returns a pointer to that struct
func unmarshalStruct1(b []bytes) (*Struct1, error) {
newStruct1 := new(Struct1)
err := json.Unmarshal(b, newStruct1)
if err != nil {
return nil, errInvalidBase64
}
return newStruct1, nil
}
// unmarshalStruct2 unmarshalls JSON []byte into a new Struct2 and returns a pointer to that struct
func unmarshalStruct2(b []bytes) (*Struct2, error) {
newStruct2 := new(Struct2)
err := json.Unmarshal(b, newStruct2)
if err != nil {
return nil, errInvalidBase64
}
return newStruct2, nil
}
// receiveStruct accepts *intermediateStruct who's Data field contains either Struct1 or Struct2
// This function needs to return either *Struct1 or *Struct2 and an error
func receiveStruct(iStruct *intermediateStruct) (*struct{}, error) {
switch iStruct.Type {
case StructType1:
struct1, err := unmarshalStruct1(iStruct.Data)
if err != nil {
return nil, err
}
// The following line is where I'm getting the type mismatch
return struct1, nil
case StructType2:
struct2, err := unmarshalStruct2(iStruct.Data)
if err != nil {
return nil, err
}
// The following line is another type mismatch
return struct2, nil
default:
return nil, errInvalidStructType
}
}
I know there's a way to do what I'm trying to achieve - I just lack the experience/understanding to get there.
Thanks for any and all input!
Your unmarshallStruct function returns a pointer to type Struct1 or Struct2 (depending on which version of the function gets called). And therefore the variables struct1 and struct2 are pointers to types Struct1 and Struct2 respectively. Neither is a pointer to type struct (which is not a real Go type anyways I must add). A struct is a keyword which helps to declare types containing fields/attributes.
Depending on the use-cases you have in mind for the rest of your code, can instead try any of the below:
As mkopriva suggested, return a interface{} object, but you'd need to use type assertion to actually make sure of the object
Define an interface which both Struct1 and Struct2 implement, and return a pointer to this
Make separate functions which work with either Struct1 or Struct2. This is not necessarily as bad as it sounds as Go lets you pass functions in the same way you'd pass types (see example of the Less() function in sort package).

How to use "reflect" to set interface value inside a struct of struct

Had a rough time trying to set the interface value by using "reflect" package. The interface value is actually inside a struct of a struct. See my code in Go Playground
Basically, inside initProc, I want to assign dummyAFunc function to DummyA field in Box struct
package main
import (
"fmt"
"reflect"
)
type Box struct {
Name string
DummyA interface{}
}
type SmartBox struct {
Box
}
func dummyAFunc(i int) {
fmt.Println("dummyAFunc() is here!")
}
func initProc(inout interface{}) {
// Using "inout interface{}", I can take any struct that contains Box struct
// And my goal is assign dummyAFunc to dummyA in Box struct
iType:=reflect.TypeOf(inout)
iValue:=reflect.ValueOf(inout)
fmt.Println("Type & value:", iType.Elem(), iValue.Elem()) // Type & value: *main.SmartBox &{{ <nil>}}
e := reflect.ValueOf(inout).Elem()
fmt.Println("Can set?", e.CanSet()). // true
fmt.Println("NumField", e.NumField()) // panic: reflect: call of reflect.Value.NumField on ptr Value ?????
fmt.Println("NumMethod", e.NumMethod()) // NumMethod = 0
}
func main() {
smartbox := new (SmartBox)
initProc(&smartbox)
}
I'm new to Go and I've read the The laws of Reflection but still can't figure it out. Please help. Thanks!
You are passing a **SmartBix to initProc. So when you dereference once with reflect's Elem() you are still getting a pointer (*Smart box).
Since new already returns a pointer, just use:
smartbox := new (SmartBox)
// InitProc(smartbox) // **SmartBox
InitProc(smartbox) // *SmartBox
https://play.golang.org/p/j4q6aq6QL_4
EDIT
To update the input struct's DummyA field, you can do something like this:
func initProc2(v interface{}) error {
if reflect.TypeOf(v).Kind() != reflect.Ptr {
return fmt.Errorf("value must be a pointer")
}
dv := reflect.ValueOf(v).Elem()
if dv.Kind() != reflect.Struct {
return fmt.Errorf("value must be a pointer to a struct/interface")
}
const fname = "DummyA" // lookup field name
f := dv.FieldByName(fname)
if !f.CanSet() {
return fmt.Errorf("value has no field %q or cannot be set", fname)
}
nv := reflect.ValueOf(dummyAFunc)
f.Set(nv)
return nil
}
Working example: https://play.golang.org/p/VE751GtSGEw

Golang assign a map to an interface

I wants to assign a map to an interface where underlying value is of type map[string]interface.
type Data struct{
data interface{}
}
result := make(map[string]interface{})
data := Data{
data:result
}
details := make(map[string]interface{})
details["CreatedFor"] = "dfasfasdf"
details["OwnedBy"] = "fasfsad"
How can I insert details value to data interface inside Data struct ?
To be able to treat an interface as a map, you need to type check it as a map first.
I've modified your sample code a bit to make it clearer, with inline comments explaining what it does:
package main
import "fmt"
func main() {
// Data struct containing an interface field.
type Data struct {
internal interface{}
}
// Assign a map to the field.
type myMap map[string]interface{}
data := Data{
internal: make(myMap),
}
// Now, we want to access the field again, but as a map:
// check that it matches the type we want.
internalMap, ok := data.internal.(myMap)
if !ok {
panic("data.internal is not a map")
}
// Now what we have the correct type, we can treat it as a map.
internalMap["CreatedFor"] = "dfasfasdf"
internalMap["OwnedBy"] = "fasfsad"
// Print the overall struct.
fmt.Println(data)
}
This outputs:
{map[CreatedFor:dfasfasdf OwnedBy:fasfsad]}

Golang interface to struct

I have a function that has a parameter with the type interface{}, something like:
func LoadTemplate(templateData interface{}) {
In my case, templateData is a struct, but each time it has a different structure. I used the type "interface{}" because it allows me to send all kind of data.
I'm using this templateData to send the data to the template:
err := tmpl.ExecuteTemplate(w, baseTemplateName, templateData)
But now I want to append some new data and I don't know how to do it because the "interface" type doesn't allow me to add/append anything.
I tried to convert the interface to a struct, but I don't know how to append data to a struct with an unknown structure.
If I use the following function I can see the interface's data:
templateData = appendAssetsToTemplateData(templateData)
func appendAssetsToTemplateData(t interface{}) interface{} {
switch reflect.TypeOf(t).Kind() {
case reflect.Struct:
fmt.Println("struct")
s := reflect.ValueOf(t)
fmt.Println(s)
//create a new struct based on current interface data
}
return t
}
Any idea how can I append a child to the initial interface parameter (templateData)? Or how can I transform it to a struct or something else in order to append the new child/data?
Adrian is correct. To take it a step further, you can only do anything with interfaces if you know the type that implements that interface. The empty interface, interface{} isn't really an "anything" value like is commonly misunderstood; it is just an interface that is immediately satisfied by all types.
Therefore, you can only get values from it or create a new "interface" with added values by knowing the type satisfying the empty interface before and after the addition.
The closest you can come to doing what you want, given the static typing, is by embedding the before type in the after type, so that everything can still be accessed at the root of the after type. The following illustrates this.
https://play.golang.org/p/JdF7Uevlqp
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
type After struct {
Before
s []string
}
func contrivedAfter(b interface{}) interface{} {
return After{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b).(After)
fmt.Println(a.m)
fmt.Println(a.s)
}
Additionally, since the data you are passing to the template does not require you to specify the type, you could use an anonymous struct to accomplish something very similar.
https://play.golang.org/p/3KUfHULR84
package main
import (
"fmt"
)
type Before struct {
m map[string]string
}
func contrivedAfter(b interface{}) interface{} {
return struct{
Before
s []string
}{b.(Before), []string{"new value"}}
}
func main() {
b := Before{map[string]string{"some": "value"}}
a := contrivedAfter(b)
fmt.Println(a)
}
You can't append data arbitrarily to a struct; they're statically typed. You can only assign values to the fields defined for that specific struct type. Your best bet is probably to use a map instead of structs for this.
Not recommended, but you can create structs dynamically using the reflect package.
Here is an example:
package main
import (
"encoding/json"
"os"
"reflect"
)
type S struct {
Name string
}
type D struct {
Pants bool
}
func main() {
a := Combine(&S{"Bob"}, &D{true})
json.NewEncoder(os.Stderr).Encode(a)
}
func Combine(v ...interface{}) interface{} {
f := make([]reflect.StructField, len(v))
for i, u := range v {
f[i].Type = reflect.TypeOf(u)
f[i].Anonymous = true
}
r := reflect.New(reflect.StructOf(f)).Elem()
for i, u := range v {
r.Field(i).Set(reflect.ValueOf(u))
}
return r.Addr().Interface()
}
You could use something like the Combine function above to shmush any number of structs together. Unfortunately, from the documentation:
StructOf currently does not generate wrapper methods for embedded fields. This limitation may be lifted in a future version.
So your created struct won't inherit methods from the embedded types. Still, maybe it does what you need.
If you are just looking to convert your interface to struct, use this method.
type Customer struct {
Name string `json:"name"`
}
func main() {
// create a customer, add it to DTO object and marshal it
receivedData := somefunc() //returns interface
//Attempt to unmarshall our customer
receivedCustomer := getCustomerFromDTO(receivedData)
fmt.Println(receivedCustomer)
}
func getCustomerFromDTO(data interface{}) Customer {
m := data.(map[string]interface{})
customer := Customer{}
if name, ok := m["name"].(string); ok {
customer.Name = name
}
return customer
}

How do you create a new instance of a struct from its type at run time in Go?

In Go, how do you create the instance of an object from its type at run time? I suppose you would also need to get the actual type of the object first too?
I am trying to do lazy instantiation to save memory.
In order to do that you need reflect.
package main
import (
"fmt"
"reflect"
)
func main() {
// one way is to have a value of the type you want already
a := 1
// reflect.New works kind of like the built-in function new
// We'll get a reflected pointer to a new int value
intPtr := reflect.New(reflect.TypeOf(a))
// Just to prove it
b := intPtr.Elem().Interface().(int)
// Prints 0
fmt.Println(b)
// We can also use reflect.New without having a value of the type
var nilInt *int
intType := reflect.TypeOf(nilInt).Elem()
intPtr2 := reflect.New(intType)
// Same as above
c := intPtr2.Elem().Interface().(int)
// Prints 0 again
fmt.Println(c)
}
You can do the same thing with a struct type instead of an int. Or anything else, really. Just be sure to know the distinction between new and make when it comes to map and slice types.
As reflect.New doesn't automatically make reference types used in struct fields, you could use something like the following to recursively initialize those field types (note the recursive struct definition in this example):
package main
import (
"fmt"
"reflect"
)
type Config struct {
Name string
Meta struct {
Desc string
Properties map[string]string
Users []string
}
}
func initializeStruct(t reflect.Type, v reflect.Value) {
for i := 0; i < v.NumField(); i++ {
f := v.Field(i)
ft := t.Field(i)
switch ft.Type.Kind() {
case reflect.Map:
f.Set(reflect.MakeMap(ft.Type))
case reflect.Slice:
f.Set(reflect.MakeSlice(ft.Type, 0, 0))
case reflect.Chan:
f.Set(reflect.MakeChan(ft.Type, 0))
case reflect.Struct:
initializeStruct(ft.Type, f)
case reflect.Ptr:
fv := reflect.New(ft.Type.Elem())
initializeStruct(ft.Type.Elem(), fv.Elem())
f.Set(fv)
default:
}
}
}
func main() {
t := reflect.TypeOf(Config{})
v := reflect.New(t)
initializeStruct(t, v.Elem())
c := v.Interface().(*Config)
c.Meta.Properties["color"] = "red" // map was already made!
c.Meta.Users = append(c.Meta.Users, "srid") // so was the slice.
fmt.Println(v.Interface())
}
You can use reflect.Zero() which will return the representation of the zero value of the struct type. (similar to if you did var foo StructType) This is different from reflect.New() as the latter will dynamically allocate the struct and give you a pointer, similar to new(StructType)
Here's a basic example like Evan Shaw gave, but with a struct:
package main
import (
"fmt"
"reflect"
)
func main() {
type Product struct {
Name string
Price string
}
var product Product
productType := reflect.TypeOf(product) // this type of this variable is reflect.Type
productPointer := reflect.New(productType) // this type of this variable is reflect.Value.
productValue := productPointer.Elem() // this type of this variable is reflect.Value.
productInterface := productValue.Interface() // this type of this variable is interface{}
product2 := productInterface.(Product) // this type of this variable is product
product2.Name = "Toothbrush"
product2.Price = "2.50"
fmt.Println(product2.Name)
fmt.Println(product2.Price)
}
Per newacct's response, using Reflect.zero it would be:
var product Product
productType := reflect.TypeOf(product) // this type of this variable is reflect.Type
productValue := reflect.Zero(productType) // this type of this variable is reflect.Value
productInterface := productValue.Interface() // this type of this variable is interface{}
product2 := productInterface.(Product) // the type of this variable is Product
This is a great article on the basics of reflection in go.
You don't need reflect and you can do this easy with factory pattern if they share the same interface:
package main
import (
"fmt"
)
// Interface common for all classes
type MainInterface interface {
GetId() string
}
// First type of object
type FirstType struct {
Id string
}
func (ft *FirstType) GetId() string {
return ft.Id
}
// FirstType factory
func InitializeFirstType(id string) MainInterface {
return &FirstType{Id: id}
}
// Second type of object
type SecondType struct {
Id string
}
func (st *SecondType) GetId() string {
return st.Id
}
// SecondType factory
func InitializeSecondType(id string) MainInterface {
return &SecondType{Id: id}
}
func main() {
// Map of strings to factories
classes := map[string]func(string) MainInterface{
"first": InitializeFirstType,
"second": InitializeSecondType,
}
// Create a new FirstType object with value of 10 using the factory
newObject := classes["first"]("10")
// Show that we have the object correctly created
fmt.Printf("%v\n", newObject.GetId())
// Create a new SecondType object with value of 20 using the factory
newObject2 := classes["second"]("20")
// Show that we have the object correctly created
fmt.Printf("%v\n", newObject2.GetId())
}

Resources