Learn what
What is an interface?
How to define interfaces?
How to use the interface?
How to embed interfaces?
How to assign values between interfaces?
How to infer the actual type of interface?
How to use an empty interface?
concept
The interface defines the rules of the implementer by defining abstract methods. The concept is a little similar to that in other languages, but for the implementation of the interface in Go language, the coupling between the interface and the interface is lower and the flexibility is higher.
In order to understand the concept of interface in a popular way, let me give you an example, "if you are entrusted by Nuwa to create people, but you have made requirements for creating people, you should have the action of eating and drinking, but it doesn't matter how everyone eats and drinks. As long as you have these two actions, you will succeed in creating people".
In this example, the requirements formulated by Nuwa are interfaces. If you do it according to the requirements of human creation, it is called the implementation of interfaces.
I don't know if it's clear. Bless you.
definition
Now define an interface for People and define two actions for eating and drinking.
type People interface { // Optional parameter name: Eat(string) error Eat(thing string) error Drink(thing string) error }
The Eat and sink methods do not need to be implemented.
func keyword is not required before method.
The parameter name and return name of the method may not be written.
After definition, you can directly declare a variable of this interface type.
var p People
The p variable is not initialized, and the value is nil.
Implementation interface
The work of interface implementation is entrusted to the user-defined type. When the user-defined type implements all the methods of the interface, it implements the interface.
type LaoMiao struct { Name string Age int } func (l LaoMiao) Eat(thing string) error { fmt.Println("Steal in the company" + thing) return nil } func (l LaoMiao) Drink(thing string) error { fmt.Println("Steal drinks in the company" + thing) return nil }
LaoMiao implements all methods in the People interface, which shows that it implements the interface.
There is no need to use the implementation keyword in other languages to implement.
Multiple interfaces can be implemented at the same time.
If you look at another picture, it may be clearer, as follows:
The "implementer" in the figure includes the methods of interfaces A and B, and it implements both interfaces.
Use of interfaces
After the interface is implemented, the instantiation of this type can be assigned to the interface type.
var p People = LaoMiao{} p.Eat("Peach") // output Stealing peaches in the company
p is the interface type, and the actual implementation is LaoMiao type.
You may wonder why I don't call it directly, like the following:
m := LaoMiao{} m.Eat("Peach")
The above code does not use the People interface type, but if I define another type to implement the People interface, the benefits will be reflected.
type LaoSun struct { Name string Age int } func (l LaoSun) Eat(thing string) error { fmt.Println("Eat in the car" + thing) return nil } func (l LaoSun) Drink(thing string) error { fmt.Println("Drink in the car" + thing) return nil }
Another type is added to implement. See that this is LaoSun and the type above is LaoMiao.
Now let's start thinking about a question. If I want to call these two types of methods, and the calling code is only written once, what should I do? Take a breath, I tell you, nature uses the interface.
// interface/main.go // ... func Run(p People) { thing1, thing2 := "Peach", "cola" p.Eat(thing1) p.Drink(thing2) } func main() { Run(LaoMiao{}) Run(LaoSun{}) } // output Stealing peaches in the company Steal coke in the company Eat peaches in the car Drink coke in the car
A Run function is added to the code. The type accepted by the function is the interface type. The main function passes the two types that implement the interface to the function.
Receiver type and interface
In the above code, all type receivers that implement interfaces are value types, for example:
func (l LaoSun) Eat(thing string) error { // ... }
The receiver l type is LaoSun. If it is a pointer, the receiver should be * LaoSun.
When calling with interface type, the type accepted by the interface is value type, for example:
Run(LaoSun{})
The parameter LaoSun {} of this function is of value type, but it can also pass the pointer type run (& LaoSun {}), and the compiler will dereference it.
If the receiver is a pointer type, the pointer type must be used when passing values to the interface, for example:
type GouDan struct { Name string Age int } func (l *GouDan) Eat(thing string) error { fmt.Println("You take care of me" + thing) return nil } func (l *GouDan) Drink(thing string) error { fmt.Println("You don't care what I drink" + thing) return nil }
Redefine a type to implement the People interface, and the receiver of the method is the pointer type. If the value type is passed to the interface, the compiler will report an error.
Run(GouDan{}) // output cannot use GouDan{} (type GouDan) as type People in argument to Run: GouDan does not implement People (Drink method has pointer receiver)
Correctly, only pointer types can be passed.
Run(&GouDan{}) or var sun *LaoSun = &LaoSun{} Run(sun)
Interface embedding
An interface may contain another interface, for example:
type Student interface { People Study() }
A Student interface is defined. Naturally, there will be eating and drinking actions for the Student interface. Therefore, there is no need to repeat the definition, just embed the People interface.
If a user-defined type wants to implement the Student interface, it needs to implement both the methods defined in the embedded interface and the methods defined by itself.
Multiple interfaces can be embedded.
Interface and interface assignment
In the above code, the People interface is embedded into the Student interface. At this time, the Student interface type variable can be assigned to the People type variable.
Example:
var stu Student var pl People = stu
If the People type is not embedded, but only the Student interface contains its methods, the above interface and interface assignment are also allowed.
type Student interface { Eat(thing string) error Drink(thing string) error Study() }
Summary: the large interface contains the methods of the small interface, and the large interface can be assigned to the small interface.
Empty interface
An empty interface means that no abstract method is defined, as follows:
type Empty interface {}
The Empty type is now an Empty interface that can accept any type.
var str Empty = "character string" var num Empty = 222
When used in normal projects, in order to make it easier, there is no need to define an empty interface, and interface {} is directly used as the type.
var str interface{} = "character string" var num interface{} = 222
Summary: all types implement empty interfaces, that is, empty interfaces can accept variables of any type.
Type inference
In an interface variable, if you want to know who the specific implementation type of the interface variable is, you need to use type inference.
1. Interface to implementer
v := var1.(T)
T indicates the type you need to infer.
v is a variable of type T after conversion.
var1 can be an empty interface.
Example:
var people People // Convert People type to LaoMiao value type people = LaoMiao{} val := people.(LaoMiao) // Convert People type to LaoMiao pointer type people = &LaoMiao{} peo := people.(*LaoMiao)
It can be seen from the example that the type stored in the interface variable must be the same as the type inferred. If not, the compiler will report an error.
people = LaoMiao{} // report errors val := people.(*LaoMiao) // correct val := people.(LaoMiao)
2. Is it inferable
If the actual type stored in the interface variable is uncertain, it must be judged. If it cannot be inferred, the compiler will report an error.
v, ok := var1.(T)
Judging is actually adding an additional return value when inferring the type. If the inferred ok value is true, otherwise it is false.
people = LaoMiao{} val1, ok := people.(*LaoMiao) fmt.Println(ok) val2, ok := people.(LaoMiao) fmt.Println(ok) // output false true
3. type-switch
This knowledge point was actually long ago Process control I've talked about it in an article. I'll say it again and add.
var data interface{} data = "111" // data is the interface type, and. (type) gets the actual type // Assign the value of the actual type to the d variable switch d := data.(type) { case string: // After entering the branch, d is of type string fmt.Println(d + "str") case int: // After entering the branch, d is of type int fmt.Println(d + 1) } // output 111str
Get the actual type of the interface through. (type). Remember that this method can only be used in switch statements, which is why I explain it here alone.
The fallthrough keyword cannot be used.
If you only judge the type, you do not need to use the d variable to accept.
summary
The interface knowledge of Go language is finished. It is very important to master it clearly. Now, do you know the essence of interface implementation?
To sum up, as long as the method is implemented, the interface is implemented. If the implemented method meets multiple interfaces, it will be implemented.