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 👊.