Подтвердить что ты не робот

Как вы создаете новый экземпляр структуры из своего типа во время выполнения в Go?

В Go, как вы создаете экземпляр объекта из его типа во время выполнения? Я полагаю, вам также понадобится сначала получить фактический type объекта?

Я пытаюсь сделать ленивый экземпляр для сохранения памяти.

4b9b3361

Ответ 1

Для этого вам нужно 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)
}

Вы можете сделать то же самое с типом структуры, а не с int. Или что-нибудь еще, действительно. Просто не забудьте узнать различие между новым и сделать, когда дело доходит до типов карт и срезов.

Ответ 2

Поскольку reflect.New автоматически не создает ссылочные типы, используемые в полях структуры, вы можете использовать что-то вроде следующего, чтобы рекурсивно инициализировать эти типы полей (обратите внимание на определение рекурсивной структуры в этом примере):

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

Ответ 3

Вы можете использовать reflect.Zero(), который вернет представление нулевого значения типа struct. (аналогично тому, как вы делали var foo StructType). Это отличается от reflect.New(), поскольку последний динамически выделяет структуру и дает вам указатель, аналогичный new(StructType)