87

Go では、実行時にその型からオブジェクトのインスタンスをどのように作成しますか? typeオブジェクトの実際の値も最初に取得する必要があると思いますか?

メモリを節約するために遅延インスタンス化を試みています。

4

5 に答える 5

91

そのためには、 が必要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 の代わりに struct 型でも同じことができます。または他の何か、本当に。マップとスライスのタイプに関しては、new と make の違いを知っておいてください。

于 2011-10-21T21:10:16.067 に答える
39

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())
}
于 2013-04-23T21:12:16.713 に答える
21

reflect.Zero()構造体型のゼロ値の表現を返す which を使用できます。(あなたがした場合と同様var foo StructType)これはreflect.New()、後者が構造体を動的に割り当ててポインターを与えるため、とは異なります。new(StructType)

于 2011-10-22T00:02:54.377 に答える
7

reflectそれらが同じインターフェースを共有している場合、ファクトリーパターンでこれを簡単に行うことができます:

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())
}
于 2018-06-18T13:54:35.917 に答える