Writing in the front

In our previous article “Method for Learning”, we learned the definition and application of Golang methods. In this article, we will learn about Goalng interface.

Interface Definition

An interface is an abstract type that defines a set of methods that need to be implemented, and the data types that implement the interface can be considered instances of the interface. An interface consists of a set of methods and an interface type. The declaration format is as follows:

typeThe interface nameinterface{method name (parameter list) (return value list)... }Copy the code

In Golang’s programming style (convention), the name of an interface that contains only one method consists of the method name with a [e]r suffix, such as Printer, Reader, Writer, Logger, Converter, and so on. There are also less common ways (when the suffix er is inappropriate), such as Recoverable, where the interface name ends with able or begins with I (as in Java).

Interfaces in the Go language are short, usually containing zero or at most three methods.

Consider the following example:

First, we declare a SpiritualRootAble interface in the interfaces package

src/go_code/interface/interfaces/spiritual_root.go

package interfaces

// Ring-root interface, the realization of ring-root interface can be practiced by mortals
type SpiritualRootAble interface {

	// Generate a root
	GenSpiritualRootNames() string

	// Get the generated root
	SpiritualRoot() string

	// Practice
	Practice()
}
Copy the code

Second, we declare a mortal structure in the Model package and implement the SpiritualRootAble interface

src/go_code/interface/model/mortal.go

package model

import (
	"crypto/rand"
	"fmt"
	"math/big"
)

/ / human
type Mortal struct {
	name ,
	gender ,
	spiritualRoot string
	age int

}

func NewMortal(name, gender string, age int) Mortal {
	mortal:=Mortal{
		name:   name,
		gender: gender,
		age:    age,
	}
	mortal.spiritualRoot = mortal.GenSpiritualRootNames()
	return mortal
}

func (recv Mortal) SpiritualRoot(a) string {
	if &recv.spiritualRoot == nil{
		return "There is no spirit root."
	}

	return recv.spiritualRoot
}

func (recv Mortal)Practice(a)  {
	fmt.Println(recv.name,"Start practicing...")}func (recv Mortal) GenSpiritualRootNames(a) string{
	gsrn := []string{
		"Golden Root"."Water root"."Wood Root"."Fire Spirit Root"."Earth spirit root"."There is no spirit root.",
	}
	index, _ := rand.Int(rand.Reader, big.NewInt(5))

	return  gsrn[index.Int64()]
}

Copy the code

Finally, we use them in Main

src/go_code/interface/main/main.go

package main

import (
	"fmt"
	"go_code/interface/interfaces"
	"go_code/interface/model"
)

func main(a) {

	 // Declares a variable of type SpiritualRootAble interface
	 var sr interfaces.SpiritualRootAble

	 // A mortal was born
	 mortal := model.NewMortal(Mr.han ""."Men".1)

	 // The interface variable points to a mortal instance
	sr = mortal

	// Obtain the spiritual roots of mortals
	fmt.Println(sr.SpiritualRoot())

	// Mortals begin to practice
	sr.Practice()

}

Copy the code

Output:

Fire spirit root Han Li began to practice...Copy the code

You can see:

In Golang, you need to explicitly declare that the type implements an interface (without class implemments interfacesName as Java does). A type implements the interface as long as it implements the set of methods defined in the interface.

A type that implements an interface can have methods other than implementing interface methods.

One type can implement multiple interfaces (in fact, mortal also implements empty interfaces, see below for more on empty interfaces).

An interface type can contain a reference to an instance whose type implements the interface (the interface is dynamically typed).

Empty interface

An empty interface is an interface that does not contain any methods. Any type implements a null interface. A null interface is somewhat similar to the concept of Object in Java

type Any interface {}
Copy the code

Interface Nested interface

An interface can contain one or more other interfaces, which is equivalent to listing the methods of these embedded interfaces directly in the outer interface.

For example, the interface File contains all the methods for ReadWrite and Lock, plus a Close() method.

type ReadWrite interface {
    Read(b Buffer) bool
    Write(b Buffer) bool
}
type Lock interface {
    Lock()
    Unlock()
}
type File interface {
    ReadWrite
    Lock
    Close()
}
Copy the code

Type assertion in Golang

For an interface type variable varI to contain any type of value, so, there must be a way to detect its dynamic type, that is, the actual type of the value stored in the runtime variable var. And that, in turn, is type assertion.

v := varI.(T)
Copy the code

Type assertions can be invalid, and while the compiler does its best to check that the conversion is valid, it cannot anticipate all possibilities. An error occurs if the conversion fails while the program is running. It is safer to use the following form for type assertions:

ifv,ok :=varI.(T); ok{ do something }Copy the code

If the conversion is valid, v is the value varI converts to T, and OK will be true; Otherwise v is zero of type T, OK is false, and no runtime errors occur.

If we just need to determine whether varI is of type T and do not need to get the value of type T, we can do this:

if_,ok := varI.(T); ok{ }Copy the code

Let’s continue with the example above for type assertions

package main

import (
	"fmt"
	"go_code/interface/interfaces"
	"go_code/interface/model"
)

func main(a) {

	 // Declares a variable of type SpiritualRootAble interface
	 var sr interfaces.SpiritualRootAble

	 // A mortal was born
	 mortal := model.NewMortal(Mr.han ""."Men".1)

	 // The interface variable points to a mortal instance
	sr = mortal

    // Type assertion
	ifv,ok :=sr.(*model.Mortal); ok{ fmt.Println(v) } }Copy the code

Output:

&{Han Li male Kim Young-geun1}
Copy the code

It is worth noting that the receiver type of our method when implementing SpiritualRootAble is *Mortal, which is the pointer type for a Mortal. So what actually implements the SpiritualRootAble interface is *Mortal, so T is *Mortal when making type assertions. We need to pay attention to this when using type assertions, otherwise the compiler will report an error.

Application of type assertions

In Golang, how do we test if a value implements an interface? The answer is through type assertions

var m interfaceTypeName
if_,ok := m.(interfaceTypeName); ok { fmt.Println(ok) }Copy the code

conclusion

An interface can be thought of as a contract that an implementation type must satisfy, describing the behavior of the type and specifying what the type can do. Interfaces completely separate what types can do and how they can do it, causing variables of the same interface to behave differently at different times, which is the essence of polymorphism.

In golang:

  • Pointer methods can be called through Pointers
  • Value methods can be called by value
  • Methods whose recipients are values can be called through Pointers because Pointers are dereferenced first
  • Methods whose recipients are Pointers cannot be called by value because the value stored in the interface has no address

When assigning a value to an interface, the compiler ensures that all possible interface methods can be called on that value, so incorrect assignments fail at compile time.

Write in the last

That’s all I have to say about Golang’s interface. The examples covered in this article can be downloaded here. If my study notes can help you, please give me a thumbs up and encouragement. If there are mistakes and omissions in the article, please help to correct them. Starting with the next article, we will start the basics series, covering reflection, file manipulation, data exchange, error handling, Go coroutines, and channels. Please subscribe to my blog 👊.