# Go Interfaces
- What are Go interfaces?
- How are they different?
- What can you do with them?
- How do I use them effectively?
π
---
## What are Go interfaces?
- Interfaces are types.
- You define a set of methods,
- which defines its shape,
- that concrete implementations satisfy.
π
----
## Example
An contrived interface for defining the behavior of an animal:
```go
type Animal interface {
Speak() string
}
```
π
---
## Conventions
- Interfaces have an "adverb" as their name.
- Methods are "verbs".
Examples:
- `Read()` and the `Reader` interface.
- `Seek()` and the `Seeker` interface.
However, naming is hardβ’ so `ServeHTTP` for the `Handler` interface breaks this convention. in the [net/http](https://pkg.go.dev/net/http) package.
π
---
## Best Practices
- [Go Proverbs](https://go-proverbs.github.io/)
- The bigger the interface the weaker the abstraction.
- `interface{}` or `any` says nothing.
π
---
## The empty interface
Let's take a closer look at the empty interface:
- `interface{}` -- Go 1.17 and earlier
- `any` -- Go 1.18+
π
----
### Example
```go
package main
import "fmt"
type cat struct {}
func (cat) Speak() string { return "Meow!" }
func main() {
var x any = &cat{}
fmt.Printf("%T\n", x)
}
```
π
----
### Example (cont)
- What does this print?
- Let's have a look: https://go.dev/play/p/gLYPeeXZh8W
- But wait?! [type any](https://pkg.go.dev/builtin#any) is the `interface{}` type?! π±
- What's going on?
π
---
## Type Assertions
- Go converts concrete types to interfaces.
- All types implement `any` or `interface{}`.
- You can type assert a value with: `cat, ok := x.(Cat)`.
- Now we can call `cat.Speak()` if `ok` is `true`.
π
---
## Live Coding Time!
- Let's live-code a more complex example...
For those following along later, here's the code for [shapes](https://git.mills.io/prologic/shapes) as well as its [documentation](https://pkg.go.dev/git.mills.io/prologic/shapes).
π
---
## Receivers Matter
- Pointer Receiver vs. Value Receiver
- Decide which one you need.
- Go doesn't care or enforce this, but:
You can end with compiler errors like this as seen on the [grow](https://git.mills.io/prologic/shapes/pulls/1) branch:
```
cannot use (Rectangle literal) (value of type Rectangle) as Shape value in variable declaration: Rectangle does not implement Shape (method Grow has pointer receiver)
```
π
---
## Interface Conformance
Takes one of two forms:
- `var _ InterfaceType = MyType{}`
- `var _ InterfaceType = (*MyTyoe)(nil)`
- πββοΈ Put these at the top of your concrete types.
π
---
## Embedding Interfaces
- Interfaces can embed other interfaces.
Example:
```go
type Shape interface {
fmt.Stringer
...
}
```
See the [stringer](https://git.mills.io/prologic/shapes/pulls/3) branch.
π
---
## Dependency Injection
And of course, interfaces are used for dependency injection!
Example:
```go
func Stats(w io.Writer, shapes ...Shape) {
for _, shape := range shape {
_, _ := fmt.Fprintf(w, "%T Area(): %0.2f", shape, shape.Area())
}
}
```
π
---
## The End π¬
- Interfaces are very simple,
- but very powerful!
- Enables good testing,
- and easier refactoring!
- Promotes good reuse,
- and architectural choices.
Use them! π