Home > Software engineering >  How to instantiate struct that is defined in different package from struct name and provide fields
How to instantiate struct that is defined in different package from struct name and provide fields

Time:01-01

Suppose I have some structs defined in package 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{
//not sure about value type^
    "Foo": Foo,     // staticcheck shows: not a type
    "Bar": Bar,     //
}
    

And I want to instantiate the structs dynamically; something like this:

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

The above clearly doesn't work.

Is it possible to achieve this? I am new to . I have looked at reflect, I have tried to build the Registry with pointers, pointers of empty instance, but couldn't figure out a way to do this.

Ultimately, I am trying to write a command line utility to change themes of certain programs. I have written program specific methods (like Show in above example), and I am trying to read the program specific params from a config.json file, and create the instances dynamically.

CodePudding user response:

If I correctly understand what you are trying to achieve, here is the way to do that:

registry.go:

package pkg

import (
    "fmt"
    "io"
)

type NewShowable func(r io.Reader) Showable

type Showable interface {
    Show()
}

type Foo struct {
    FieldA string
    FieldB string
}

func newFoo(r io.Reader) Showable {
    // Read config from r and construct Foo
    return Foo{}
}

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

type Bar struct {
    FieldA string
    FieldB string
}

func newBar(r io.Reader) Showable {
    // Read config from r and construct Bar
    return Bar{}
}

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

var Registry = map[string]NewShowable{
    "Foo": newFoo,
    "Bar": newBar,
}

main.go:

package main

import (
    "log"
    "os"

    "url/user/pkg"
)

func main() {
    f, err := os.Open("config.json")
    if err != nil {
        log.Fatalln(err)
    }
    defer f.Close()
    foo := pkg.Registry["Foo"](f)

    f2, err := os.Open("config2.json")
    if err != nil {
        log.Fatalln(err)
    }
    defer f2.Close()
    bar := pkg.Registry["Bar"](f2)
    foo.Show()
    bar.Show()
}
  • Related