studio programacion para móviles libro edición desarrollo curso consultas aplicaciones go reflection go-reflect

go - para - manual de programacion android pdf



¿Cómo se crea una nueva instancia de una estructura de su tipo en tiempo de ejecución en Go? (5)

Aquí hay un ejemplo básico como Evan Shaw dio, pero con una estructura:

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

Según la respuesta de newacct, usando Reflect.zero sería:

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

Este es un gran artículo sobre los conceptos básicos de la reflexión en go.

En Go, ¿cómo se crea la instancia de un objeto de su tipo en tiempo de ejecución? ¿Supongo que también necesitarías obtener primero el type real del objeto?

Estoy intentando hacer instancias perezosas para ahorrar memoria.


Como reflect.New no hace automáticamente que los tipos de referencia se utilicen en los campos de estructura, podría usar algo como lo siguiente para inicializar recursivamente esos tipos de campo (observe la definición de estructura recursiva en este ejemplo):

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


No necesita reflect y puede hacerlo fácilmente con el patrón de fábrica si comparten la misma interfaz:

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


Para hacer eso, necesitas 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) }

Puede hacer lo mismo con un tipo de estructura en lugar de un int. O cualquier otra cosa, realmente. Solo asegúrese de conocer la distinción entre new y make cuando se trata de tipos de mapas y sectores.


Puede usar reflect.Zero() que devolverá la representación del valor cero del tipo de estructura. (similar a si hiciera var foo StructType ) Esto es diferente de reflect.New() ya que este último asignará dinámicamente la estructura y le dará un puntero, similar a new(StructType)