es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Cómo instanciar una estructura definida en un paquete diferente al nombre de la estructura y proporcionar campos.

Supongamos que tengo algunas estructuras definidas en el paquete “pkg”:

package pkg

type Foo struct {
    FieldA string
    FieldB string
}

type Bar struct {
    FieldA string
    FieldB string
}

func (Foo) Show() {
    fmt.Println("Foo")
}

func (Bar) Show() {
    fmt.Println("Bar")
}

type Showable interface {
    Show()
}

Registry := map[string]Showable{
    "Foo": Foo,
    "Bar": Bar,
}

Y quiero instanciar las estructuras dinámicamente; algo como esto:

package main

import "url/user/pkg"

func main() {
    foo := pkg.Registry["Foo"]{
        FieldA: "A",
        FieldB: "B",
    }

    bar := pkg.Registry["Bar"]{
        FieldA: "X",
        FieldB: "Y",
    }
    foo.Show()
    bar.Show()
}

Esto claramente no funciona.

¿Es posible lograr esto? Soy nuevo en Go. He visto “reflect”, he intentado construir el “Registry” con punteros, punteros de instancia vacía, pero no pude encontrar una manera de hacerlo.

En última instancia, estoy tratando de escribir una utilidad de línea de comandos para cambiar temas de ciertos programas. He escrito métodos específicos del programa (como “Show” en el ejemplo anterior) y estoy tratando de leer los parámetros específicos del programa desde un archivo “config.json” y crear las instancias dinámicamente.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Sí, es posible lograr esto utilizando reflexión en Go.

    Puede crear una función que tome un puntero a una estructura y un mapa de nombres de campos y valores, y luego establezca los valores de los campos utilizando reflexión.

    Aquí tienes un ejemplo:

    func SetStructValues(s interface{}, values map[string]interface{}) {
        v := reflect.ValueOf(s).Elem()
        for fieldName, fieldValue := range values {
            field := v.FieldByName(fieldName)
            if field.IsValid() {
                field.Set(reflect.ValueOf(fieldValue))
            }
        }
    }
    

    Luego puedes usar esta función para instanciar tus estructuras dinámicamente:

    fooInstance := reflect.New(reflect.TypeOf(pkg.Foo{})).Elem()
    SetStructValues(fooInstance.Addr().Interface(), map[string]interface{}{
        "FieldA": "A",
        "FieldB": "B",
    })
    foo := fooInstance.Interface().(pkg.Foo)
    
    barInstance := reflect.New(reflect.TypeOf(pkg.Bar{})).Elem()
    SetStructValues(barInstance.Addr().Interface(), map[string]interface{}{
        "FieldA": "X",
        "FieldB": "Y",
    })
    bar := barInstance.Interface().(pkg.Bar)
    

    Este código crea una nueva instancia de Foo y Bar utilizando reflexión, establece los valores de sus campos utilizando la función SetStructValues y luego obtiene los tipos concretos llamando a Interface() y haciendo una aserción de tipo.

    Luego puedes usar foo y bar como cualquier otra instancia de sus respectivas estructuras.

    Espero que esto sea útil!

Comments are closed.