2011-10-21 28 views
37

Trong Go, làm thế nào để bạn tạo ra thể hiện của một đối tượng từ loại của nó tại thời gian chạy? Tôi cho rằng bạn cũng cần phải nhận được type thực tế của đối tượng trước?Làm thế nào để bạn tạo ra một thể hiện mới của một cấu trúc từ loại của nó tại thời gian chạy trong Go?

Tôi đang cố gắng thực hiện quá trình khởi tạo chậm để tiết kiệm bộ nhớ.

Trả lời

44

Để thực hiện điều đó, bạn cần 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) 
} 

Bạn có thể làm điều tương tự với loại cấu trúc thay vì int. Hoặc bất cứ điều gì khác, thực sự. Chỉ cần chắc chắn để biết sự khác biệt giữa mới và thực hiện khi nói đến bản đồ và các loại slice.

+0

đăng phiên bản câu trả lời này cho các cấu trúc bên dưới –

15

Bạn có thể sử dụng reflect.Zero() để trả về giá trị bằng không của loại cấu trúc. (Tương tự như nếu bạn đã làm var foo StructType) Đây là khác biệt so với reflect.New() vì sau đó tự động sẽ phân bổ các struct và cung cấp cho bạn một con trỏ, tương tự như new(StructType)

18

Như reflect.New không tự động làm cho các loại tài liệu tham khảo sử dụng trong lĩnh vực cấu trúc, bạn có thể sử dụng một cái gì đó như sau đệ quy khởi tạo những kiểu trường (lưu ý định nghĩa struct đệ quy trong ví dụ này):

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

nên 'chuyển đổi ft.Type.Kind()' là 'chuyển ft.Kind()'? – nos

+0

ft biến là loại StructField, Kind() chính nó là một phương pháp từ reflect.Type struct – Bilal

0

Dưới đây là một ví dụ cơ bản như Evan Shaw cho, nhưng với một cấu trúc:

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) 

} 

mỗi phản ứng newacct của, sử dụng Reflect.zero nó sẽ là:

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 về những điều cơ bản của sự phản ánh trong khi di chuyển.

Các vấn đề liên quan