# Structs and Interfaces

Although it would be possible for us to write programs only using Go's built-in data types, at some point it would become quite tedious. Consider a program that interacts with shapes:

```package main

import ("fmt"; "math")

func distance(x1, y1, x2, y2 float64) float64 {
a := x2 – x1
b := y2 – y1
return math.Sqrt(a*a + b*b)
}
func rectangleArea(x1, y1, x2, y2 float64) float64 {
l := distance(x1, y1, x1, y2)
w := distance(x1, y1, x2, y1)
return l * w
}
func circleArea(x, y, r float64) float64 {
return math.Pi * r*r
}
func main() {
var rx1, ry1 float64 = 0, 0
var rx2, ry2 float64 = 10, 10
var cx, cy, cr float64 = 0, 0, 5

fmt.Println(rectangleArea(rx1, ry1, rx2, ry2))
fmt.Println(circleArea(cx, cy, cr))
}```

Keeping track of all the coordinates makes it difficult to see what the program is doing and will likely lead to mistakes.

## Structs

An easy way to make this program better is to use a struct. A struct is a type which contains named fields. For example we could represent a Circle like this:

```type Circle struct {
x float64
y float64
r float64
}```

The `type` keyword introduces a new type. It's followed by the name of the type (`Circle`), the keyword `struct` to indicate that we are defining a `struct` type and a list of fields inside of curly braces. Each field has a name and a type. Like with functions we can collapse fields that have the same type:

```type Circle struct {
x, y, r float64
}```

### Initialization

We can create an instance of our new Circle type in a variety of ways:

`var c Circle`

Like with other data types, this will create a local Circle variable that is by default set to zero. For a `struct` zero means each of the fields is set to their corresponding zero value (`0` for `int`s, `0.0` for `float`s, `""` for `string`s, `nil` for pointers, …) We can also use the new function:

`c := new(Circle)`

This allocates memory for all the fields, sets each of them to their zero value and returns a pointer. (`*Circle`) More often we want to give each of the fields a value. We can do this in two ways. Like this:

`c := Circle{x: 0, y: 0, r: 5}`

Or we can leave off the field names if we know the order they were defined:

`c := Circle{0, 0, 5}`

### Fields

We can access fields using the `.` operator:

```fmt.Println(c.x, c.y, c.r)
c.x = 10
c.y = 5```

Let's modify the `circleArea` function so that it uses a `Circle`:

```func circleArea(c Circle) float64 {
return math.Pi * c.r*c.r
}```

In main we have:

```c := Circle{0, 0, 5}
fmt.Println(circleArea(c))```

One thing to remember is that arguments are always copied in Go. If we attempted to modify one of the fields inside of the `circleArea` function, it would not modify the original variable. Because of this we would typically write the function like this:

```func circleArea(c *Circle) float64 {
return math.Pi * c.r*c.r
}```

And change main:

```c := Circle{0, 0, 5}
fmt.Println(circleArea(&c))```

## Methods

Although this is better than the first version of this code, we can improve it significantly by using a special type of function known as a method:

```func (c *Circle) area() float64 {
return math.Pi * c.r*c.r
}```

In between the keyword `func` and the name of the function we've added a “receiver”. The receiver is like a parameter – it has a name and a type – but by creating the function in this way it allows us to call the function using the `.` operator:

`fmt.Println(c.area())`

This is much easier to read, we no longer need the `&` operator (Go automatically knows to pass a pointer to the circle for this method) and because this function can only be used with `Circle`s we can rename the function to just `area`.

Let's do the same thing for the rectangle:

```type Rectangle struct {
x1, y1, x2, y2 float64
}
func (r *Rectangle) area() float64 {
l := distance(r.x1, r.y1, r.x1, r.y2)
w := distance(r.x1, r.y1, r.x2, r.y1)
return l * w
}```

`main` has:

```r := Rectangle{0, 0, 10, 10}
fmt.Println(r.area())```

### Embedded Types

A struct's fields usually represent the has-a relationship. For example a `Circle` has a `radius`. Suppose we had a person struct:

```type Person struct {
Name string
}
func (p *Person) Talk() {
fmt.Println("Hi, my name is", p.Name)
}```

And we wanted to create a new `Android` struct. We could do this:

```type Android struct {
Person Person
Model string
}```

This would work, but we would rather say an Android is a Person, rather than an Android has a Person. Go supports relationships like this by using an embedded type. Also known as anonymous fields, embedded types look like this:

```type Android struct {
Person
Model string
}```

We use the type (`Person`) and don't give it a name. When defined this way the `Person` struct can be accessed using the type name:

```a := new(Android)
a.Person.Talk()```

But we can also call any `Person` methods directly on the `Android`:

```a := new(Android)
a.Talk()```

The is-a relationship works this way intuitively: People can talk, an android is a person, therefore an android can talk.

## Interfaces

You may have noticed that we were able to name the `Rectangle`'s `area` method the same thing as the `Circle`'s `area` method. This was no accident. In both real life and in programming, relationships like these are commonplace. Go has a way of making these accidental similarities explicit through a type known as an Interface. Here is an example of a `Shape` interface:

```type Shape interface {
area() float64
}```

Like a struct an interface is created using the `type` keyword, followed by a name and the keyword `interface`. But instead of defining fields, we define a “method set”. A method set is a list of methods that a type must have in order to “implement” the interface.

In our case both `Rectangle` and `Circle` have area methods which return `float64`s so both types implement the `Shape` interface. By itself this wouldn't be particularly useful, but we can use interface types as arguments to functions:

```func totalArea(shapes ...Shape) float64 {
var area float64
for _, s := range shapes {
area += s.area()
}
return area
}```

We would call this function like this:

`fmt.Println(totalArea(&c, &r))`

Interfaces can also be used as fields:

```type MultiShape struct {
shapes []Shape
}```

We can even turn `MultiShape` itself into a `Shape` by giving it an area method:

```func (m *MultiShape) area() float64 {
var area float64
for _, s := range m.shapes {
area += s.area()
}
return area
}```

Now a `MultiShape` can contain `Circle`s, `Rectangle`s or even other `MultiShape`s.

### Problems

• What's the difference between a method and a function?

• Why would you use an embedded anonymous field instead of a normal named field?

• Add a new method to the `Shape` interface called `perimeter` which calculates the perimeter of a shape. Implement the method for `Circle` and `Rectangle`.

 ← Previous Index Next →