Preface
The go language does not have object-oriented concepts. The interface mentioned by go language is different from the interface mentioned by java, c++ and other languages. It does not display the instructions that the interface is implemented, and there are no keywords for inheritance, subclassing, and implements.
1. Overview
In Go language, interfaces contain two meanings:It is both a collection of methods and a type. It is implicitly implemented in Go, which means that for a specific type, there is no need to declare which interfaces it implements, but only the methods required for the interface are provided.
The go language implements interface functions in an implicit way, which is relatively flexible.
Features of Go language interface:
- interface is a collection of methods or behavior declarations
- The interface interface method is relatively implicit. Any type of object implements all the methods contained in the interface, which indicates that the type implements the interface.
- The interface can also be used as a general type, and other type variables can assign values to the variables declared by the interface.
- interface can be used as a data type, and any object that implements the interface can assign values to the corresponding interface type variable.
2. Interface type
2.1 Definition of interface
Each interface type consists of any method signature, and the definition format of the interface is as follows:
type interface type name interface{
Method name 1 (parameter list 1) Return value list 1
Method name 2 (parameter list 2) Return value list 2
…
}
illustrate
-
Interface type name: Use type to define the interface as a custom type name. When naming the Go language interface, it will usually be added after the word.
er
, if there is a write operation interface, it is calledWriter
, an interface with string function is calledStringer
, the interface with a shutdown function is calledCloser
wait. It is best to highlight the type meaning of the interface. - Method name: When the first letter of the method name is capitalized and the first letter of the interface type name is also capitalized, this method can be accessed by code outside the package where the interface is located.
- Parameter list, return value list: Parameter variable names in the parameter list and return value list can be ignored.
For example, define aWrite
MethodWriter
interface.
type writer interface{ Write([]byte) error }
2.2 Conditions for implementing interfaces
The interface specifies aList of methods to implement, in Go language, a type is only implementedAll methods specified in the interface, then we call it implementing this interface.
Example
DefinedEater
Interface type, which contains aEat
method.
// Eater interfacetype Eater interface { Eat() }
There is oneDog
The structure type is as follows.
type Dog struct {}
becauseEater
The interface contains only oneEat
Method, so just giveDog
Add a structureEat
The method can satisfyEater
Interface requirements.
//Dog type Eat methodfunc (d Dog) Eat() { ("Eat bones!") }
This is calledDog
ImplementedEater
interface.
Complete code
// Eater interfacetype Eater interface { Eat() } type Dog struct {} //Dog type Eat methodfunc (d Dog) Eat() { ("Eat bones!") } func main() { dog := Dog{} () }
2.3 Why do interfaces need
In most cases, data may contain different types, but it has one or more common points, which are the basis of abstraction.
Example
// Eater interfacetype Eater interface { Eat() } type Dog struct {} //Dog type Eat methodfunc (d Dog) Eat() { ("Dogs like to eat bones!") } type Cat struct {} func (c Cat) Eat(){ ("Kitten likes to eat fish!") } func main() { dog := Dog{} () cat := Cat{} () }
From an animal, you can abstract iteat
Method, even if other animals are expanded, they only need to be implementedEater interface
In-houseEat()
The method can be doneeat
Calling this action.
An interface can be understood as an abstraction of a certain aspect, which can be many-to-one (multiple types implement one interface), which is also a manifestation of polymorphism.
2.4 Interface type variables
An interface-type variable can store all type variables that implement the interface.
For example in the above example,Dog
andCat
All types are implementedEater
Interface, at this timeEater
Variables of type can be receivedCat
andDog
Variable of type.
var x Eater // Declare a variable x of type Eatera := Cat{} // Declare a Cat type variable ab := Dog{} // Declare a Dog type variable bx = a // You can directly assign Cat type variable to x() // Kittens like to eat fish!x = b // You can directly assign Dog type variables to x() // Dogs like to eat bones!
3. Value receiver and pointer receiver
The following example shows the difference between implementing an interface using a value receiver and a pointer receiver.
Define aMover
interface, it contains aMove
method.
// Mover defines an interface typetype Mover interface { Move() }
3.1 Value receiver implementation interface
We define aDog
Structure type and define one for it using the value receiverMove
method.
// Dog Dog structure typetype Dog struct{} // Move uses the value receiver to define the Move method to implement the Mover interfacefunc (d Dog) Move() { ("The dog will move") }
Implementation at this timeMover
The interface isDog
type.
var x Mover // Declare a variable x of type Mover var d1 = Dog{} // d1 is Dog typex = d1 // You can assign d1 to variable x() var d2 = &Dog{} // d2 is Dog pointer typex = d2 // You can also assign d2 to variable x()
From the above code, we can find that after using the value receiver to implement the interface, both the structure type and the corresponding structure pointer type variable can be assigned to the interface variable.
3.2 Pointer receiver implements interface
Let's test again what's the difference between using pointer receivers to implement interfaces.
// Cat Cat Structure Typetype Cat struct{} // Move uses pointer receiver to define the Move method to implement the Mover interfacefunc (c *Cat) Move() { ("The cat will move") }
Implementation at this timeMover
The interface is*Cat
Type, we can*Cat
Variables of type are assigned directly toMover
Interface type variablesx
。
var c1 = &Cat{} // c1 is *Cat typex = c1 // Can treat c1 as Mover type()
But can't giveCat
Assign value toMover
Interface type variablesx
。
// The following code cannot be compiledvar c2 = Cat{} // c2 is Cat typex = c2 // Cannot treat c2 as Mover type
Since there is syntactic sugar for evaluating pointers in Go, there is no problem with the interface implemented by the value receiver whether it is using the value type or the pointer type. But we don't always have to address a value, so extra attention should be paid to the interface implemented by the pointer receiver.
4. The relationship between type and interface
4.1 Implement multiple interfaces in one type
A type can implement multiple interfaces at the same time, and the interfaces are independent of each other and the other's implementation is unknown.
Example
Animals not only have the attributes of eating, but also have the attributes of movement. You can define two interfaces to enable the same animal to achieve these two attributes separately.
// Eater interfacetype Eater interface { Eat() } // Mover interfacetype Mover interface { Move() } type Dog struct {} //Dog type Eat methodfunc (d Dog) Eat() { ("Dogs like to eat bones!") } //Dog type Move methodfunc (d Dog) Move(){ ("Dogs love to play!") } func main() { //Initialize the structure dog := Dog{} //dog implements two interfaces: Eater and Mover eat := dog move := dog () //Calling the Eat method on the Eat type () //Calling the Move method on the Mover type}
Structures in the programDog
The methods in the Eater and Mover interfaces are implemented respectively.
4.2 Implement the same interface in multiple types
Different types in Go can also implement the same interface.
All methods of an interface do not necessarily need to be fully implemented by one type. Interface methods can be implemented by embedding other types or structures in the type.
// Washing Machinetype WashingMachine interface { wash() dry() } // Dryertype dryer struct{} // Implement the dry() method of the WashingMachine interfacefunc (d dryer) dry() { ("Shake") } // washing machinetype haier struct { dryer //Embed into the shunt dryer} // Implement the Wash() method of the WashingMachine interfacefunc (h haier) wash() { ("Scrub brush") } func main() { h := haier{} () () }
5. Interface nesting
New interface types can be formed by nesting each other. For example, Go standard libraryio
There are many examples of interfaces combining with each other in the source code.
// src/io/ type Reader interface { Read(p []byte) (n int, err error) } type Writer interface { Write(p []byte) (n int, err error) } type Closer interface { Close() error } // ReadWriter is a new interface type formed by combining Reader interface and Writer interfacetype ReadWriter interface { Reader Writer } // ReadCloser is a new interface type formed by combining the Reader interface and the Closer interface.type ReadCloser interface { Reader Closer } // WriteCloser is a new interface type formed by combining the Writer interface and the Closer interface.type WriteCloser interface { Writer Closer }
For this new interface type formed by a combination of multiple interface types, it is also necessary to implement all the methods specified in the new interface type to be implemented in order to implement the interface type.
The interface can also be used as a field in the structure. Let's take a look at a Go standard library.sort
Examples in the source code.
// src/sort/ // Interface defines the interface type that sorts elements through indexestype Interface interface { Len() int Less(i, j int) bool Swap(i, j int) } // The Interface interface is embedded in the reverse structuretype reverse struct { Interface }
By embedding an interface type in the structure, the structure type implements the interface type, and the method of the interface can also be overridden.
// Less Add Less method to reverse type and rewrite the Less method of the original Interface interface typefunc (r reverse) Less(i, j int) bool { return (j, i) }
Interface
Type originalLess
The method signature isLess(i, j int) bool
, rewritten here as(j, i)
, that is, invert the index parameters by swapping the position.
Another thing to note in this example isreverse
The structure itself is not exportable (the first letter of the structure type name is lowercase),Define an exportable
Reverse
Functions to let users createreverse
Structure instance.
func Reverse(data Interface) Interface { return &reverse{data} }
The purpose of this is to ensure thatreverse
In the structureInterface
The attribute must not benil
, no(j, i)
A null pointer panic will appear.
VI. Empty interface
An interface in Golang can not define any method, and an interface without any method is an empty interface.An empty interface means there are no constraints, so any type of variable can implement an empty interface.
Empty interfaces are used a lot in actual projects, and the use of empty interfaces can represent any data type.
Example
func main() { //Define an empty interface x, the x variable can receive any data type var x interface{} str := "Hello Go" x = str ("type:%T,value:%v\n",x,x) num := 10 x = num ("type:%T,value:%v\n",x,x) bool := true x = bool ("type:%T,value:%v\n",x,x) }
Running results
type:string,value:Hello Go
type:int,value:10
type:bool,value:true
1. Empty interface as a parameter of a function
// Empty interface as function parameterfunc show(a interface{}) { ("type:%T value:%v\n", a, a) } func main() { show(1) show(true) show(3.14) var mapStr = make(map[string]string) mapStr["name"] = "Leefs" mapStr["age"] = "12" show(mapStr) }
Running results
type:int value:1
type:bool value:true
type:float64 value:3.14
type:map[string]string value:map[age:12 name:Leefs]
2. Map's value implements an empty interface
func main() { // The empty interface is used as the map value var studentInfo = make(map[string]interface{}) studentInfo["name"] = "Jeyoo" studentInfo["age"] = 18 studentInfo["married"] = false (studentInfo) }
Running results
map[age:18 married:false name:Jeyoo]
3. Slicing implements empty interface
func main() { var slice = []interface{}{"Jeyoo", 20, true, 32.2} (slice) }
Running results
[Jeyoo 20 true 32.2]
7. Type Assertion
The value of an interface (referred to as an interface value) is composed of two parts: a specific type and a specific type of value. These two parts are called the dynamic type and dynamic value of the interface respectively.
If we want to determine the type of value in an empty interface, then we can use the type assertion at this time, its syntax format:
x.(T)
illustrate
- x: represents a variable of type interface{}
- T: Indicates the type that x may be
This syntax returns two parameters. The first parameter is a variable converted to a T type, and the second value is a Boolean value. If true, it means the assertion is successful, and if false, it means the assertion fails.
Example
func main() { var x interface{} x = "Hello GO" v, ok := x.(string) if ok { (v) } else { ("Type assertion failed") } }
In the above example, if you want to assert multiple times, you need to write multiple if judgments. At this time, we can use the switch statement to implement it:
Notice: Type.(type) can only be used in combination with switch statements
// justifyType type asserts the incoming empty interface type variable xfunc justifyType(x interface{}) { switch v := x.(type) { case string: ("x is a string,value is %v\n", v) case int: ("x is a int is %v\n", v) case bool: ("x is a bool is %v\n", v) default: ("unsupport type!") } }
Since interface type variables can dynamically store different types of values, many beginners will abuse interface types (especially empty interfaces) to achieve convenience in the encoding process.
Interfaces need to be defined only if there are two or more specific types that must be processed in the same way. Remember not to add unnecessary abstraction to use interface types, resulting in unnecessary runtime loss.
Summarize
In Go language, interfaces are a very important concept and feature. Using interface types can realize the abstraction and decoupling of code, and can also hide the internal implementation of a certain function. However, the disadvantage is that it is not convenient to find the specific implementation type of interface when viewing the source code.
I believe that many readers will have many doubts when they first come into contact with interface types. Please remember that interfaces are a type, an abstract type. Different from the concrete types (integral, array, structure type, etc.) we mentioned in the previous chapter, it is an abstract type that only requires the implementation of a specific method.
The above is the detailed explanation of the Golang interface usage tutorial. For more information about the Golang interface, please pay attention to my other related articles!