26

I am beginner in golang and was trying interfaces. I want to keep interfaces in a separate packages so that I can use it to implement this in various other packages, also provide it to other teams (.a file) so that they can implement custom plugins. Please see example below on what I would like to achieve.

--- Folder structure ---
gitlab.com/myproject/
                  interfaces/
                            shaper.go
                  shapes/
                        rectangle.go
                        circle.go

---- shaper.go ---
package interfaces

type Shaper interface{

    Area() int

}

How do I ensure that the rectangle.go implements shaper interface? I understand that go implements interfaces implicitly, does this mean rectangle.go automatically implements shaper.go even though it is in a different package?

I tried it like below, but when I run gofmt tool, it removes the import because it is unused.

--- rectangle.go ---
package shapes

import "gitlab.com/myproject/interfaces"

type rectangle struct{

  length int
  width int
}

func (r rectangle) Area() int {
 return r.length * r.width
}

Thanks in advance.

Sanketh
  • 353
  • 1
  • 4
  • 7
  • 4
    What do you mean "it didn't work"? –  Jun 03 '17 at 17:11
  • 1
    You can refer to interfaces from other packages just like anything else (`interfaces.Shaper` in your case). I don't see any real problem in this question as such; you should clarify what problem you have (preferably through a [mcve]). – Martin Tournoij Jun 03 '17 at 17:16
  • 1
    I have explained a bit more about the issue i face. I think that this is a minimal complete and verifiable example. could you please explain with code about referring or implementing the interface with example in this context? Thanks in advance. – Sanketh Jun 03 '17 at 17:36
  • You don't need to import an interface to implement it. In Go a type matches any interface that specifies a subset of the methods defined for the type. – md2perpe Jun 03 '17 at 17:43
  • @md2perpe I understand that go implements interfaces implicitly, does this mean rectangle.go automatically implements shaper.go even though it is in a different package? – Sanketh Jun 03 '17 at 17:54
  • 2
    You do not need to import the interface. Where you implement an interface is not important - only where it is used. There is more information on interfaces [here](https://gobyexample.com/interfaces) and [here](http://jordanorelli.com/post/32665860244/how-to-use-interfaces-in-go) – Paul Coleman Jun 03 '17 at 17:57
  • 1
    @Sanketh Yes, the interface neither has to be in the same package nor be imported for a type to implement it. – md2perpe Jun 03 '17 at 18:22
  • Related, introduction to interfaces: [Why are interfaces needed in Golang?](https://stackoverflow.com/questions/39092925/why-are-interfaces-needed-in-golang/39100038#39100038) – icza Jun 04 '17 at 08:01
  • @md2perpe exactly – Abhishek D K May 26 '22 at 12:18

2 Answers2

28

There is an excellent section in the go wiki about interfaces:

Go interfaces generally belong in the package that uses values of the interface type, not the package that implements those values. The implementing package should return concrete (usually pointer or struct) types: that way, new methods can be added to implementations without requiring extensive refactoring.

This also has the advantage that it reduces coupling between packages (by not forcing anybody to import your package just for the interface) and it generally leads to smaller interfaces (by allowing people to consume only a subset of the interface that you would have built).

If you are new to go I highly recommend reading the "Go Code Review Comments" wiki article I linked and if you have some more time also Effective Go. Happy hacking!

Friedrich Große
  • 2,383
  • 19
  • 19
  • 1
    I often see this suggestion not being followed. For instance, in net/http, handler interface requires ServeHTTP, and is implemented by ServeMux and HandlerFunc. https://golang.org/pkg/net/http/#ServeMux.ServeHTTP – imagineerThat Mar 30 '18 at 04:06
  • 1
    Its true that the ServerMux implements the http.Handler interface but at the same time this type *uses* the interface to let the caller inject the handler interface she wants (e.g. via the ServeMux.Handle(…) function. – Friedrich Große Mar 31 '18 at 08:01
  • 1
    Do you also recommend reading https://dave.cheney.net/2016/08/20/solid-go-design? – overexchange Mar 28 '19 at 17:45
  • does it mean if I have multiple places where I want to use the interface (multiple consumers), I just re-define the interface within the respective package of those consumers? – Quan Ding Feb 27 '23 at 21:48
  • Yes exactly; each new package can define precisely the interface that they need. This should drive you towards smaller interfaces because each consumer can define exactly what they need and ignore everything else. As a result, your code and also your unit tests will be more focused on the package's business logic.If you already have a small interface, copying it is typically a small price compared to what you gain in reduced coupling. – Friedrich Große Mar 01 '23 at 09:42
1

Let's say you have a function that uses a Shaper. You can test the function with a rectangle, and by doing so ensuring the implementation:

func DoStuff(s Shaper) {
    s.Area()
}

func TestDoStuff(t *testing.T) {
    var s Shaper = rectangle{length: 5, width: 3}
    DoStuff(s)
    // assertion
}

If rectangle does not implement Shaper, you'll get an error like this:

cannot use rectangle literal (type rectangle) as type Shaper in assignment:
rectangle does not implement Shaper (missing Area method)

Effective Go:

Interfaces in Go provide a way to specify the behavior of an object: if something can do this, then it can be used here.

Lan Quach
  • 72
  • 2