Uberswe
Uberswe

Reputation: 1058

How should I declare an interface that has a method to return a slice of a different interface?

Here is an example that I created where I declare my first struct which is a Toolbox that contains a slice Hammers. I made an interface for Toolbox and Hammer so that others can use my functions without having to use my structs as long as they follow my interface implementation.

package main

import "fmt"

type ToolboxInterface interface {
    GetHammers() []HammerInterface
}

type HammerInterface interface {

}

type Toolbox struct {
    Hammers []Hammer
}

func (t Toolbox)GetHammers() []HammerInterface  {
    return []HammerInterface{t.Hammers}
}

type Hammer struct {
    Color string
}

func CountHammersInToolbox(t ToolboxInterface) int {
    hammers := t.GetHammers()
    return len(hammers)
}

func main()  {
    toolbox := Toolbox{Hammers: []Hammer{
        {Color: "Red"},
        {Color: "Blue"},
        {Color: "Green"}}}

    fmt.Println(len(toolbox.Hammers))

    fmt.Println(CountHammersInToolbox(toolbox))
}

My ToolboxInterface declares the GetHammers() method which I have implemented. However the CountHammersInToolbox method returns 1 instead of 3 as seen in the output.

uberswe$ go run scratch/main.go 
3
1

I have tried different variations of this but I feel a bit stuck. I don't understand why it is returning 1 but I suspect that I am declaring my interface method in the wrong way.

How should I declare an interface that has a method to return a slice of a different interface?

Upvotes: 2

Views: 58

Answers (1)

Jonathan Hall
Jonathan Hall

Reputation: 79556

There's nothing wrong with your interface definitions. The problem is that you're not properly converting []Hammer to []HammerInterface. It looks like you expect this to happen magically, but it doesn't.

In this bit of code:

func (t Toolbox) GetHammers() []HammerInterface  {
    return []HammerInterface{t.Hammers}
}

You're probably expecting that the returned result is a slice of 3 HammerInterfaces, but instead, you're getting a single HammerInterface, which is actually a slice of three Hammerss.

You must do this conversion manually. See this post for more details.

func (t Toolbox) GetHammers() []HammerInterface  {
    hammerInterfaces := make([]HammerInterface, len(t.Hammers))
    for i, hammer := range t.Hammers {
        hammerInterfaces[i] = t.Hammers[i]
    }
    return hammerInterfaces
}

In most real-world scenarios, your error would be caught by the compiler, because your slice of hammers (t.Hammers) would not satisfy the HammerInterface interface, but in your case, since that interface is empty, it matches any type, as interface{} would.

Upvotes: 5

Related Questions