#Can i iterate through package modules like i can in python?

12 messages · Page 1 of 1 (latest)

quick nymph
#

I have a folder containing multiple packages (each a seperate module), and i want to iterate through each package and call a "Name" variable from each one, so that i can print out a name and description of each package then call its respective run function. in python there is the __import__ function. is there something similar to this for go?

fair ocean
#

Is your intention to create some kind of plugin/module system for your application? If so, I would not implement it this way in Go.

quick nymph
fair ocean
#

Apart from accessing the Name variable in each package, what do you intend to do?

quick nymph
#

call a run function

#

similar to abstract base class

fair ocean
#

I'll leave the abstract base class thing for another day. I would not implement what you're describing the way you've done it in Python in Go.

#

There is a reasonably common pattern for this kind of thing though, which is to create a kind of "registry" of things.

#

Here's how it works:
First, let's describe an interface for starting/stopping (or whatever operations make sense) the components of your application

type Component interface {
  Start() error
}

In the root of your plugins package, create a global registry, something like this:

var Components map[string]Component

func Register(name string, comp Component) {
  Components[name] = comp
}

Now in each sub-package, where each component is defined, use the init function to add that package's component(s) to the registry:

// package1/component.go
func init() {
  components.Register("package1", &Component1{})
}
// package2/component.go
func init() {
  components.Register("package2", &Component2{})
}
#

After package initialization, the Components map will have registered all imported package components. Which means you could do something like this, for example:

for name, c := range components.Components {
  fmt.Println("Starting", name)
  if err := c.Start(); err != nil {
    return fmt.Errorf("failed to start components %s: %w", name, err)
  }
}
quick nymph
fair ocean
#

If you want to see a fully elaborated version of this pattern, I'll offer 2 such examples:

  1. From the standard library: database/sql (register: https://cs.opensource.google/go/go/+/refs/tags/go1.19.4:src/database/sql/sql.go;l=44)
  2. From open source: https://github.com/influxdata/telegraf (check for example the input plugin registry here: https://github.com/influxdata/telegraf/blob/master/plugins/inputs/registry.go and a registration here: https://github.com/influxdata/telegraf/blob/master/plugins/inputs/cpu/cpu.go#L166)