Methods and Interfaces in Go
Published: 2021-01-26 16:48:22

In the last blog, we looked at functions in Go. Let's move 1 step forward.

## Methods and receivers

Consider the program
```go
package main

import (
	"fmt"
)

type Point struct {
	x, y int
}

func tenfold(p Point) Point {
	return Point{p.x * 10, p.y * 10}
}

func main() {
	q := Point{4, 5}
	fmt.Println(tenfold(q))
}
```
This prints `{40 50}` as the answer.

This function can be rewritten as a method. A **method** in Go is a function with a special *receiver* argument (more about receivers in a moment). The above function can be written as
```go
func (p Point) tenfold() Point {
	return Point{p.x * 10, p.y * 10}
}

func main() {
	q := Point{4, 5}
	fmt.Println(q.tenfold())
}
```
Here, the **tenfold** method has a *receiver* of **type Point** named **p**. This function prints the same result of `{40 50}`.

Methods are not limited to receivers of struct types. The only condition for the receiver is that the receiver type must be defined in the same package as the method. Thus, built-in types like `int` or `float64` cannot be used directly as receiver types. To do so, define a custom type first
```go
type MyInt int
```
Now, you can use `MyInt` as a receiver which will take an integer value.

**Note:** Functions with a pointer/value argument can only take a pointer/value respectively, but methods with a pointer/value receiver can take either a pointer or value.

## Interfaces

In the above example, `tenfold() Point` is defined as a *method signature.* This leads into the next segment, interfaces. Interfaces are abstract types that are a set of method signatures. Values of these interface types can have any value that implements *all* the methods in that interface. Phew, that's enough of theory, now let's look at some code to understand interfaces.

```go
package main

import (
	"fmt"
)

type Point struct {
	x, y int
}

type MyInt int

type Operations interface {
	double()
}

func (p Point) double() {
	fmt.Println(Point{p.x * 2, p.y * 2})
}

func (number MyInt) double() {
	fmt.Println(number * 2)
}

func main() {
	var q Operations = Point{4, 5}
	var n Operations = MyInt(6)
	q.double()
	n.double()
}
```

We have defined the `double()` method on both the `Point` and the `MyInt` types, and added the method to the `Operations` interface. We declare variables `q` and `n` to be of type Operations, and assign a Point and MyInt value to them respectively. We call the double() method, giving the output
```
{8 10}
12
```

The part `(p Point) double()` indicates that type Point implements the Operations interface (as the interface has the `double` method), but this does not need to be declared explicitly. Thus, a type implements an interface by implementing its methods.

If we were to add the `tenfold()` method from before to our code, but only define it for the Point type, we would get a compilation error saying `MyInt does not implement Operations (missing tenfold method)`. 

```go
type Operations interface {
	tenfold() Point
	double()
}

func (p Point) tenfold() Point {
	return Point{p.x * 10, p.y * 10}
}

func (p Point) double() {
	fmt.Println(Point{p.x * 2, p.y * 2})
}

func (number MyInt) double() {
	fmt.Println(number * 2)
}

func main() {
	var q Operations = Point{4, 5}
	var n Operations = MyInt(6)
	fmt.Println(q.tenfold())
	q.double()
	n.double()
}
```
Compilation error: 
```
cannot use MyInt(6) (type MyInt) as type Operations in assignment:
MyInt does not implement Operations (missing tenfold method)
```
Thus, for a type to implement an interface, all the methods of that interface have to be defined for that particular type.

**Note:** Not all interface methods have to be called. For example, the `fmt` package has a Stringer interface:
```go
type Stringer interface {
    String() string
}
```
[From the documentation:](https://golang.org/pkg/fmt/)
"If an operand implements method String() string, that method will be invoked to convert the object to a string, which will then be formatted as required by the verb (if any)."

Thus, if the `String() string` method is defined, the print functions will invoke the Stringer interface automatically, i.e. without explicitly calling the String() method. [Click here for an example of the Stringer interface in action.](https://tour.golang.org/methods/17)

Further reading:
- [Tour of Go](https://tour.golang.org/methods/1)