Golang Interfaces
Tags: go, interface, beginners
Published: 2020-05-29 20:50:47

## What is an Interface?

> An **interface** defines a set of methods without their  **implementation**. Also an interface cannot contains variables. An interface is declared in the format:

```go
type Namer interface {
	Method(params) return type
}
```

Namer is a interface type. The name of an interface is formed by the method name plus the [er] suffix, such as Logger, Converter, Writer, and so on.

Go interfaces can have values that are a variable of the interface type or an interface value. 

> The interface variable both contains the value of the receiver value and a pointer to the appropriate method in a method table.

```go
var anI Namer
```

### An Example of Interface:

```go
package main

import "fmt"

type Shaper interface {
	Area() float32
}

type Sqaure struct {
	side float32
}

func (sq *Square) Area(){
	return sq.side * sq.side
}

func main(){
	square := new(Square)
	square.side = 10
	areaInterface := Shaper(square)
	fmt.Printf("The square has area: %f\n", areaInterface.Area())
}
```

In the program above, we define an interface **Shaper**, with one method **Area()** returning **float32** value and a struct of type **Square**, with one field **side** of type **float32**. We define a method **Area()** that can be called by a pointer to the **Square** type object. This method returns the area of a **square sq**. The struct **Square** implements the interface **Shaper**. Now, the interface variable contains a reference to the **Square** variable, and through it, we can call the method **Area()** on **Square**.

### An Example from the standard library:

```go
type Reader interface {
    Read(p []byte) (n int, err error)
}
```

### If we define a variable **reader** like this:

```go
var reader io.Reader
// then the following is correct code
reader = os.Stdin
reader = bufio.NewReader(r)
reader = new(bytes.Buffer)
f,_ := os.Open("test.txt")
reader = bufio.NewReader(f)
```

### Practice Time:

```go
package main

import "fmt"

type Simpler interface {
	Get() int
	Set(n int)
}

type Simple struct {
	n int
}

func (si *Simple) Get() int {
	return si.n
}

func (si *Simple) Set(n int) {
	si.n = n
}
func FI(it Simpler) int {
	it.Set(10)
	return it.Get()
}

func main() {
	fmt.Println("Interface")

	s := new(Simple)
	inF := Simpler(s)
	fmt.Println(FI(inF))
	// shorthand 
	var sh Simple
	fmt.Println(FI(&sh))
}
```

### What I have done in the above code:

Define an interface `Simpler` with methods `Get()`, which returns an integer, and `Set()` which has an integer as a parameter. Make a struct type `Simple`, which implements this interface.

Then, define a function that takes a parameter of the type `Simpler` and calls both methods upon it. Call this function from `main` to see if it all works correctly.

## Embedded Interface and Type Assertions

An **`interface`** can contain the name of one (or more) interface(s), which is equivalent to explicitly enumerating the methods of the embedded interface in the containing interface.

```go
type ReadWrite interface {
  Read(b Buffer) bool
  Write(b Buffer) bool
}
 
type Lock interface {
  Lock()
  Unlock()
}
 
type File interface {
  ReadWrite
  Lock
  Close()
}
```

### Detecting and converting the type of an interface variable

An interface type variable `varI` can contain a value of any type; we must have a means to detect this dynamic type, which is the actual type of the value stored in the variable at run time. The dynamic type may vary during execution but is always assignable to the type of the interface variable itself.

In general, we can test if `varI` contains at a certain moment a variable of type `T` with the type assertion test:

```go
// unchecked type assertion
v := varI.(T) 

// checked type assertion
if v, ok := varI.(T); ok { 
Process(v)
return
}else{
	// here varI is not of type T
}
```

> **Note**: Always use the `comma`, `ok` form for type assertions

```go
if v, ok := varI.(T); ok {
// ...
}
```

### Type Assertions:

```go
package main

import (
	"fmt"
	"math"
)

type Shaper interface {
	Area() float32
}

type Square struct {
	side float32
}

func (s *Square) Area() float32 {
	return s.side * s.side
}
func (ci *Circle) Area() float32 {
	return ci.radius * ci.radius * math.Pi
}

type Circle struct {
	radius float32
}

func main() {
	var aInf Shaper
	square := new(Square)
	// circle := new(Circle)
	square.side = 5
	// circle.radius = 10
	aInf = square
	// useing if, comma, ok
	if t, ok := aInf.(*Square); ok {
		fmt.Printf("The type of aInf is: %T\n", t)
	}
	if t, ok := aInf.(*Circle); ok {
		fmt.Printf("The type of aInf is: %T\n", t)
	} else {
		fmt.Println("aInf does not contain a variable of type Circle")
	}
	// using type switch
	switch t := aInf.(type) {
	case *Square:
		fmt.Printf("Type Square %T with value %v\n", t, t)

	case *Circle:
		fmt.Printf("Type Circle %T with value %v\n", t, t)

	default:
		fmt.Printf("Unexpected type %T", t)
	}

	fmt.Printf("The square has area: %f\n", aInf.Area())
}
```

### Type assertion Example

```go
package main

import "fmt"

type Simpler interface {
	Get() int
	Set(n int)
}

type Simple struct {
	n int
}

func (p *Simple) Get() int {
	return p.n
}

func (p *Simple) Set(u int) {
	p.n = u
}

type RSimple struct {
	n int
}

func (p *RSimple) Get() int {
	return p.n
}

func (p *RSimple) Set(u int) {
	p.n = u
}

func FI(it Simpler) int {
	switch it.(type) {
	case *Simple:
		it.Set(15)
		return it.Get()
	case *RSimple:
		it.Set(10)
		return it.Get()
	}
	return 0
}
func main(){
	var simpler Simple
	var rSimple RSimple
	// &simple is required because Get() is defined with the type pointer as receiver
	fmt.Println(FI(&simple))
	// &rSimple is required because Get() is defined with the type pointer as receiver
	fmt.Println(FI(&rSimple))
}
```
___
# Thanks for Reading🌹
If you'd like to keep in touch with me, follow me on [Twitter!](https://twitter.com/AliTonoy) DMs are open.