100

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.

Jonathan Hall
  • 75,165
  • 16
  • 143
  • 189
Mat Ryer
  • 3,797
  • 4
  • 26
  • 24

5 Answers5

108

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.

Evan Shaw
  • 23,839
  • 7
  • 70
  • 61
  • 1
    posted a version of this answer for structs below – Peter Berg Feb 08 '18 at 22:42
  • Do I have to instantiate it based on some object or pointer to the object? I'm using struct. I want it to take the struct itself (not its instantiated object), get its type, and instantiate it using reflection. Or, I want to somehow uses reflect.New(something) to instantiate an object without actually just instantiate the struct the usual way, as that something is supposed to be passed in to the code from a function parameter. How would I do that? – huggie Feb 08 '20 at 11:44
  • @huggie I am looking for something like that as well. Have you managed to find a solution? – Vivere Aug 15 '22 at 10:05
  • @Vivere I don't think a solution exist, but I did a work around. I wanted to be able to instantiate using string, so I ended up with a registration map of string to struct instances. I end up having to register in advance instances of type of structs I want to be able to to use reflection to instantiate. – huggie Aug 16 '22 at 06:20
44

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())
}
Alec Thomas
  • 19,639
  • 4
  • 30
  • 24
Sridhar Ratnakumar
  • 81,433
  • 63
  • 146
  • 187
25

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)

newacct
  • 119,665
  • 29
  • 163
  • 224
19

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.

Peter Berg
  • 6,006
  • 8
  • 37
  • 51
  • 4
    Whats the point of product2 := productInterface.(Product) when one can product2 := Product{} – user2846569 Jul 05 '18 at 12:13
  • The problem is that without typing Product I can't json.Unmarshal to such value. So for json package this seems to be pointless. – Kamil Dziedzic Jun 14 '20 at 17:13
  • Peter, is there a way to json.Unmarshal without typing 'Product'. I'm thinking if I were to save the type of a struct to file and then unmarshal it back to that type (type info also read from file) all happening during runtime ? My problem is I'll have to list out the different structs in my code like Product, Receipt, Delivery etc etc and cast it in code. – Dhiwakar Ravikumar Jul 30 '22 at 15:04
11

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())
}
Srdjan Grubor
  • 2,605
  • 15
  • 17