Reputation: 27
I am learning Go at the moment and I write a small project with some probes which report to a internal Log. I have a basic probe and I want create new probes extending the basic probe.
I want save the objects in an array/slice LoadedProbes.
type LoadableProbe struct {
Name string
Probe Probe
Active bool
}
var LoadableProbes []LoadableProbe
The basic probe struct is:
type ProbeModule struct {
version VersionStruct
name string
author string
log []internals.ProbeLog
lastcall time.Time
active bool
}
func (m *ProbeModule) New(name string, jconf JsonConfig) {
// read jsonConfig
}
func (m *ProbeModule) Exec() bool {
// do some stuff
return true
}
func (m *ProbeModule) String() string {
return m.name + " from " + m.author
}
func (m *ProbeModule) GetLogCount() int {
return len(m.log)
}
[...]
I am using this basic struct for other probes, for example:
type ShellProbe struct {
ProbeModule
}
func (s *ShellProbe) New(name string, jconf JsonConfig) {
s.ProbeModule.New(name, jconf)
fmt.Println("Hello from the shell")
}
func (s *ShellProbe) Exec() bool {
// do other stuff
return true
}
during Init() I call the following code:
func init() {
RegisterProbe("ShellProbe", ShellProbe{}, true)
}
func RegisterProbe(name string, probe Probe, state bool) {
LoadableProbes = append(LoadableProbes, LoadableProbe{name, probe, state})
}
The Problem is now that I can't add the type Shellprobe the the LoadableProbe struct, which expects a Probe struct.
My idea was to use interface{} instead the Probe struct in the Loadable Probe struct. But when I call the New() method of the Probe object:
for _, p := range probes.LoadableProbes {
probe.Probe.New(probe.Name, jconf)
}
But I got the error: p.Probe.New undefined (type interface {} is interface with no methods)
how can I solve this problem?
Upvotes: 1
Views: 127
Reputation: 4422
If you will have common data fields in each probe type, you might consider using Probe
as a concrete base type defining your base data fields and base methods, and using a new ProbeInterface
interface as an abstract base type defining common expected method signatures to allow you to pass around / collect / manage different specialized probe types.
You would embed Probe
into each specialized probe type, and methods and fields would be promoted according to rules of embedding. It looks like you're familiar with embedding in general, but the details are worth reviewing in the "Embedding" section of Effective Go if you haven't looked at it recently.
You could override Probe
methods in specialized probe types to execute type-specific code.
It might look something like this:
type ProbeInterface interface {
New()
Exec() bool
// whatever other methods are common to all probes
}
type Probe struct {
// whatever's in a probe
}
func (p *Probe) New() {
// init stuff
}
func (p *Probe) Exec() bool {
// exec stuff
return true
}
// Probe's methods and fields are promoted to ShellProbe according to the rules of embedding
type ShellProbe struct {
Probe
// any specialized ShellProbe fields
}
// override Probe's Exec() method to have it do something ShellProbe specific.
func (sp *ShellProbe) Exec() bool {
// do something ShellProbe-ish
return true
}
type LoadableProbe struct {
Name string
P ProbeInterface
Active bool
}
func RegisterProbe(name string, probe ProbeInterface, state bool) {
LoadableProbes = append(LoadableProbes, LoadableProbe{name, probe, state})
}
Upvotes: 1
Reputation: 79516
There are different approaches to your question.
The most direct answer would be: You need to convert your interface{}
to a concrete type before calling any methods on it. Example:
probe.Probe.(ShellProbe).New(...)
But this is a really confusing API to use.
A better approach is probably to re-think your entire API. It's hard to do this level of design thinking with the limited information you've provided.
I don't know whether this will work for you, but a common pattern is to define an interface:
type Probe interface {
New(string, JsonConfig)
Exec() bool
// ... etc
}
Then make all of your probe types implement the interface. Then use that interface instead of interface{}
, as you initially did:
type LoadableProbe struct {
Name string
Probe Probe
Active bool
}
Then your syntax should work again, because the Probe
interface includes a New
method.
probe.Probe.New(...)
Upvotes: 0