Go Structs for programmers
Tags: go, beginners, tutorial
Published: 2024-04-14 13:13:01

Here's an introduction to Go structs. This tutorial is aimed at readers who are familiar with at least on other programming language. I've omitted pointers as they may be too advanced for non C/C++ developers.

```Go
type Square struct {
    Side int
}
```

This is a square & it has one field: `side`. Let's add a simple method to it, to calculate its perimeter. Unlike most non .NET programming languages, fields & methods are *capitalized* on the basis of their being *public* or *private*. Here `Side` is capitalized as it's a public field. 

Methods are created outside the `struct` body.

```Go
func (s Square) Perimeter() int {
    return 4 * s.Side
}
```

Devs from other languages, may be confused as to why there's an `(s Square)` before the method name. 

### In Go, the *implicit* variable is *explicit* 

i.e. instead of using `this` (Java, C++, ECMAScript, C#) or `self` (Python), we explicitly declare a variable `s` of type `Square`. It marks the function as a method of `Square` & allows us to use fields & methods of the current instance.

Let's add another method `area` & make both their return types float64, (we'll see why later).

```Go
func (s Square) Perimeter() float64 {
    return float64(4 * s.Side)
}

func (s Square) Area() float64 {
    return float64(s.Side * s.Side)
}
```

Let's create another struct for circles.

```Go
type Circle struct {
    Radius int
}

func (c Circle) Diameter() int {
    return c.Radius * 2
}

func (c Circle) Perimeter() float64 {
	return c.Circumference()
}

func (c Circle) Circumference() float64 {
	return math.Pi * float64(c.Diameter())
}

func (c Circle) Area() float64 {
	return math.Pi * math.Pow(float64(c.Radius),float64(2))
}
```

I want to draw your attention to the last 2 methods. We cannot simply do ```math.Pow(c.Radius, 2)```. The compilation would fail as `math.Pow` [expects 2 float64 arguments](https://pkg.go.dev/math#Pow). There are no other versions, since 
> Go **does not support overloading** despite being a typed language.

Also, in `Circumference`, since `c.Radius` is declared as an `int`, multiplying it with a `float64` returns an `int`, & hence the *cast* is needed. This cast wouldn't be necessary while multiplying a `float64` with an `int` literal (eg: `f1 * 5` vs `f1 * float64(i1)`) .

## Interfaces (this isn't polymorphism)

Suppose we want to create an array containing shapes, & find each their respective perimeter & area, as below.

```go
arr := [4]Shape{ Circle{5} , Circle{7}, Square{15}, Triangle{8, 5, 4} }
for _,sh := range arr {
    fmt.Println(sh.Perimeter())
    fmt.Println(sh.Area())
}
```

We would need to create an **interface** `Shape`. Go interfaces aren't like your *traditional* super-classes like Java, C++ or C#. There's no `struct Foo implements Bar` kind of code involved. 

It actually embodies the 

> walks like a duck, quacks like a duck, is a duck

principle, a bit similar to ECMAScript i.e. 

> struct implements all methods specified in an interface ⇔ struct *implements* the interface

We'll just add the below interface.

```go
type Shape interface {
    Area() float64
    Perimeter() float64
}
```

That's it. `Circle`, `Triangle` & `Square` implement Shape automatically. Can you now infer why, our even our `Square` methods had to return `float64`?

That's all folks. To know more about structs especially about using pointers you can take the [tour of Go](https://go.dev/tour/moretypes/2).