-2

I'm trying to get better at using interfaces in Go to describe specific functionality, and using interface composition to write better, more understandable code. I ran into this problem which seems like it would be a common use case of go interfaces, yet I can't seem to figure out the proper syntax to use for this application. Here's some code to help explain what I am trying to do:

// Initializable is an interface to an object that can be initialized.
type Initializable interface {
    Initialize() error
}

// InitializeAll initializes an array of members.
func InitializeAll(members []Initializable) error {
    for _, member := range members {
        err := member.Initialize()
        if err != nil {
            return err
        }
    }
    return nil
}

// Host is an interface to an object providing a set of handlers for a web host.
type Host interface {
    Initializable
    Hostname() string
    RegisterHandlers(router *mux.Router)
}

// ConfigureHosts configures a set of hosts and initializes them.
func ConfigureHosts(hosts []Host) (*mux.Router, error) {
    err := InitializeAll(hosts) // compiler error here
}

This is the error: cannot use hosts (type []Host) as type []Initializable in argument InitializeAll.

My initial thought was that I was missing some sort of type downcast, which I know works for single interface objects, but had difficulty casting an array. When I tried doing err := InitializeAll(hosts.([]Initializable)), I got the following error: invalid type assertion: hosts.([]Initializable) (non-interface type []Host on left).

I'd appreciate any ideas as it comes to the design of this code example, and perhaps any suggestions as to proper syntax or some refactoring that I could do to solve this problem. Thanks!

Morgan G
  • 34
  • 4
  • 2
    See the official faq. The error tells all there is to know. – Volker Dec 27 '19 at 18:09
  • Converting a value `va` of type `interface A` to a new value `vb` of type `interface B` involves a run-time check, that the concrete type in `va` implements `interface B` (see https://golang.org/ref/spec#Assignability, or really better here, https://golang.org/ref/spec#Type_assertions). So to convert a slice of such interfaces, you need a loop, with each element being converted, with a runtime check at each conversion. – torek Dec 27 '19 at 19:25
  • In this case, since `Host` by definition includes `Initializable`, all the type assertions are guaranteed to succeed (and we could hope the compiler optimizes them away). However, a loop that does all the type assertions you'd need is just as long as writing out the loop with direct calls to `member.Initialize()`, so there's no real point in converting `[]Host` to `[]Initializable`: just do the loop and call `Initialize`. – torek Dec 27 '19 at 19:34

1 Answers1

2

I can't seem to figure out the proper syntax to use for this application

There is no such syntax. You simply cannot do this (directly).

Volker
  • 40,468
  • 7
  • 81
  • 87