Golang tutorial - 7 struct and interface
Tags: go, beginners, tutorial
Published: 2020-06-12 00:42:39

## OOP in Go
Object-oriented programming (OOP) is a common pattern in many programming languages. Object-oriented programming has many advantages like reusability, polymorphism, and encapsulation. The concept of OOP can be implemented using Go but with a different approach. Some concepts in OOP like class, interface, and methods are supported in Go but there is no type hierarchy. In Golang's official documentation in the FAQ section there is an interesting answer to the question "Is Go an object-oriented language?" that you can check [here](https://golang.org/doc/faq#Is_Go_an_object-oriented_language)

## Pointer
Pointer is an addressing mechanism that is supported in Go. In pointer, there are two operators called addressing or pointing into certain variables (`&`) and dereference (`*`). 

Let's take a look at this example:
```go
func main() {
	a := 42
	//prints out the value of a
	fmt.Println("value of a: ", a)

	//prints out the memory address that pointing to "a" variable
	fmt.Println("memory address of a: ", &a)
}
```
Output:
```
value of a:  42
memory address of a:  0xc000014080
```
Based on that code, the `&` operator addresses certain variables. 

With a pointer, a variable is capable of addressing another variable. For example, a `b` variable can be addressed into another variable (in this code the variable is called `a`). Here is the code example based on that case.
```go
func main() {
	a := 42
	//prints out the value of a
	fmt.Println("value of a: ", a)

	//prints out the memory address that pointing to "a" variable
	fmt.Println("memory address of a: ", &a)

	b := &a
	//prints out the memory address of "b" variable
	fmt.Println("value of b:", b)

	//to prints out the value of b, use *  (dereference) operator
	fmt.Println("value of b using * operator: ", *b)
}
```
Output:
```
value of a:  42
memory address of a:  0xc000014080
value of b: 0xc000014080
value of b using * operator:  42
```
Notice that the value of b and the value of a are equal because the `b` variable contains the memory address that same as `a` variable.

The illustration looks like this.
![Pointer illustration](https://dev-to-uploads.s3.amazonaws.com/i/th7meuesq1p3ri0ugdaq.png)

If the value of `a` changes, the value of `b` also changes.

```go
//changes the value of "a"
a = 45
fmt.Println("value of a: ", a)
fmt.Println("value of b: ", *b)
```
Output:
```
value of a:  45
value of b:  45
```

The `new()` function can be used to create a new pointer based on the given type. This is the basic structure of using `new()` function.

```
new(data_type)
```

This is an example.

```go
package main

import (
	"fmt"
)

type product struct {
	name  string
	price float64
}

func main() {
	// create a pointer of integer
	intPointer := new(int)

	// assign value
	*intPointer = 24

	// create a pointer of struct
	productPointer := new(product)

	// assign fields
	productPointer.name = "apple"
	productPointer.price = 8000

	fmt.Printf("the type of intPointer is %T\n", intPointer)
	fmt.Printf("the value of intPointer: %v\n", *intPointer)

	fmt.Printf("the type of productPointer is %T\n", productPointer)
	fmt.Printf("the value of productPointer: %v\n", *productPointer)
}

```

Output

```
the type of intPointer is *int
the value of intPointer: 24
the type of productPointer is *main.product
the value of productPointer: {apple 8000}
```

## struct
Class is a concept that is mainly used in OOP. In Go, there is a similar concept in class called `struct`. To declare a `struct` can be done by using this syntax:
```go
type structName struct {
	//field name type
    member int
    member2 string
    member3 []string
}
```
Here is an example of using `struct`. This struct illustrates a person that has a behavior to say something.
```go
// declare a struct called person
type person struct {
	name string
	age  int
}

// declare a method say() with type person as receiver
func (p *person) say() {
	fmt.Println("Hello, my name is: ", p.name)
}
```
To use the defined struct, assign defined struct into variable like this:
```go
//instantiate the person
p1 := person{name: "Enki Gilbert", age: 42}
//call a method say()
p1.say()
```
Here it is the complete code:
```go
package main

import "fmt"

// declare a struct called person
type person struct {
	name string
	age  int
}

// declare a method say() with type person as receiver
func (p *person) say() {
	fmt.Println("Hello, my name is: ", p.name)
}

func main() {
	//instantiate the person
	p1 := person{name: "Enki Gilbert", age: 42}
	// call a method say()
	p1.say()
}

```
Output:
```
Hello, my name is:  Enki Gilbert
```
The alternative syntax of using a defined struct can be done by ignoring the field name.
```go
//instantiate the person
p1 := person{"Enki Gilbert", 42}
```
The anonymous struct is also available in Go.
```go
s1 := struct{
	//declare some fields
	field1 int
	field2 []string
}{
	//instantiate directly
	field1: 12,
	field2: []string{"hi","mate"},
}
```
## Composition
The inheritance feature isn't supported in Go, we can use the composition mechanism instead. Here is the example of `struct` composition:
```go
package main

import "fmt"

// declare a struct called person
type person struct {
	name string
	age  int
}

// composition example
// declare a struct called manager that includes another struct called person
type manager struct {
	person
	team string
}

// declare a method say() with type person as receiver
func (p *person) say() {
	fmt.Println("Hello, my name is: ", p.name)
}

func main() {
	//instantiate the person
	p1 := person{"Enki Gilbert", 42}

	//instantiate the manager and assign person field by using p1 variable
	m1 := manager{person: p1, team: "Racing Team Solvalou"}

	//the say() method is still available
	m1.say()

}

```
Output:
```
Hello, my name is:  Enki Gilbert
```
Based on that code, we declare a struct called `manager` that composes another struct called `person`. The `say()` method is still available to the `manager` struct because it composes another struct (`person`) that has a `say()` method.

The alternative syntax of instantiating the struct that has a struct composition:
```go
//instatiate the person struct into person field directly
m1 := manager{person: person{"Enki Gilbert", 42}, team: "Racing Team Solvalou"}
```
## Interface
Interface is a powerful concept in programming. The interface is similar to struct but it only contains some abstract methods. In Go, the interface defines a generic abstraction of behaviors. To declare an interface can be done by using this syntax:
```go
//type name interface
type name interface {
	//declare some methods
	method1()
	method2() int
}
```
Here is an example of using the interface.
```go
package main

import "fmt"

// declare a rectangle struct
type rectangle struct {
	length int
	width  int
}

// declare an interface with area() as a member
type shape interface {
	area() int
}

// declare a method area()
// the rectangle struct implements area() method in shape interface
func (r *rectangle) area() int {
	return r.length * r.width
}

// declare a method with type shape as a parameter
func info(s shape) {
	fmt.Println("the area: ", s.area())
}

func main() {
	r1 := rectangle{12, 12}
	//r1 is a rectangle type. rectangle implements all methods in shape interface.
	info(&r1)
}

```
Output:
```
the area:  144
```
Based on that example, we declare a struct called `rectangle` and an interface called `shape`. The `rectangle` implements an `area()` method in the `shape` interface. There is a method called `info()` with `shape` type as a parameter. The `info()` method's parameter is accessible for every struct that implements all methods in the `shape` interface. 

If there is another struct, in this case, called `square`. The `info()` method is also available because the `square` struct also implements all methods in the `shape` interface.
```go
type square struct {
	side int
}
//the square struct implements area() method in shape interface
func (s *square) area() int {
	return s.side * s.side
}

```
Here is the complete example:
```go
package main

import (
	"fmt"
)

// declare a rectangle struct
type rectangle struct {
	length int
	width  int
}

// declare a square struct
type square struct {
	side int
}

// declare an interface with area() as a member
type shape interface {
	area() int
}

// declare a method area()
// the rectangle struct implements area() method in shape interface
func (r *rectangle) area() int {
	return r.length * r.width
}

// the square struct implements area() method in shape interface
func (s *square) area() int {
	return s.side * s.side
}

//declare a method with type shape as a parameter
/**
anything that implements all methods in shape interface is considered as a shape in general.
for this case the rectangle and square is a shape because implements all methods in shape interface
**/
func info(s shape) {
	fmt.Println("the area: ", s.area())
}

func main() {
	r1 := rectangle{12, 12}
	info(&r1)

	s1 := square{25}
	info(&s1)
}

```
Output:
```
the area:  144
the area:  625
```
The composition of the interface is also available. The example can be checked in `io` package [here](https://golang.org/src/io/io.go#L120).

## Method sets
A method set is a function that is associated with a certain type. For example, the `area()` is a function associated with the `shape` type. If the receiver of the method set is a value, then the method can be used by a value or a pointer of a value.
For example, this `area()` method is available for the value and pointer of type `shape` (in this example is a rectangle).
```go
//shape interface
type shape interface {
	area() int
}
func (r rectangle) area() int {
	return r.length * r.width
}
//used in info() function
func info(s shape) {
	fmt.Println("the area: ", s.area())
}
func main() {
	r1 := rectangle{12, 12}
	//with value
	info(r1)
	//with pointer
	info(&r1)
}
```
Output:
```
the area:  144
the area:  144
```
If the receiver of the method set is a pointer, then the method is **only** available with the pointer.

Example:
```go
//the receiver is a pointer
func (r *rectangle) area() int {
	return r.length * r.width
}

func info(s shape) {
	fmt.Println("the area: ", s.area())
}

func main() {
	r1 := rectangle{12, 12}
	//with value, throw an error
	// info(r1)
	//with pointer
	info(&r1)
}
```
Output:
```
the area:  144
```
## Notes
- Learn more about struct in [here](https://go.dev/ref/spec#Struct_types)
- Learn more about pointers in [here](https://go.dev/ref/spec#Pointer_types)
- Learn more about method sets in [here](https://go.dev/ref/spec#Method_sets)

I hope this article is helpful to learn the Go programming language. If you have any thoughts or feedback, you can write it in the discussion section below.