1. Definition of the interface
An interface is an agreement with the caller. It is a highly abstract type and does not need to be tied to specific implementation details. Interface to do is to define good convention, tell the caller what they can do, but do not know its internal implementation, which we have seen and the specific type, such as int
, map
, slice
etc. are not the same.
Define and structure the interface is slightly different, though all to type
begin the keyword, but the keyword interface is interface
representing the type of a custom interface.
That person
is an interface, which has two methods sayName() string
and sayAge() int
, as a whole shown in the following code:
type person interface {
sayName() string
sayAge() int
}
}
For person
the interface, it will tell the caller through its sayName()
acquisition method name string, through its sayAge()
acquisition of age method, which is the agreed interface. As for how the string is obtained and what it looks like, the interface does not care, and the caller does not need to care, because these are done by the implementer of the interface.
2. Implementation of the interface
Interface must be implemented by a particular type to student
the structure, for example,
type student struct {
name string
age int
}
It is achieved person
interfaces, as shown in the following code:
func (s student) sayName() string {
fmt.Printf("name is %v\n", s.name)
return s.name
}
func (s student) sayAge() int {
fmt.Printf("name is %v\n", s.age)
return s.age
}
Type structure to student
define a method that in the method signature, and an interface (name, parameters and return values) the same, so the structure student
is realized person
interface.
Note: If an interface has multiple methods, then each method that needs to implement the interface is considered to implement the interface.
3. Interface Assignment
Interface assignment Go
divided into the following two situations languages:
- Assign the object instance to the interface;
- Assign one interface to another interface.
3.1 Assign object instance to interface
First discuss the assignment of a certain type of object instance to the interface, which requires the object instance to implement all the methods required by the interface, as follows:
type Integer int
func (a Integer) Less(b Integer) bool {
return a < b
}
func (a *Integer) Add(b Integer) {
*a += b
}
Correspondingly, we define the interface LessAdder
as follows:
type LessAdder interface {
Less(b Integer) bool
Add(b Integer)
}
Now there is a question: Suppose we define an Integer
object instance types, how to assign it to LessAdder
the interface it?
Should I use the following statement (1) or statement (2)?
var a Integer = 1
var b LessAdder = &a ... (1)
var b LessAdder = a ... (2)
The answer is that the sentence (1) should be used. The reason is that the Go
language can be based on the following functions:
func (a Integer) Less(b Integer) bool {
return a < b
}
Automatically generate a new Less()
method:
func (a *Integer) Less(b Integer) bool {
return (*a).Less(b)
}
Thus, the type *Integer
exists both Less()
methods, there are Add()
methods to meet LessAdder
the interface.
On the other hand, according to
func (a *Integer) Add(b Integer)
This function cannot automatically generate the following member method:
func (a Integer) Add(b Integer) {
(&a).Add(b)
}
Because (&a).Add()
change is only a function of the parameters a, subject to external influence is not practical to operate, which is not consistent with the
expectations of users.
Therefore, the Go
language does not automatically generate this function for it. Thus, the type Integer
there is only Less()
a method, the lack of Add()
a method, does not satisfy LessAdder
the interface, therefore the above statements (2) can not be assigned.
To further demonstrate the above reasoning, we may wish to define an Lesser
interface as follows:
type Lesser interface {
Less(b Integer) bool
}
Then define an Integer
object instance of type, assign it to Lesser
the interface:
var a Integer = 1
var b1 Lesser = &a ... (1)
var b2 Lesser = a ... (2)
As we expected, both statement (1) and statement (2) can be compiled and passed.
3.2 Assign one interface to another interface
In Go
language, as long as both interfaces have the same list of methods (different order does not matter), then they are equivalent, can be assigned to each other.
4. Interface call
Implements person
the interface after use. First of all I would like to define a print person
function interface, as follows:
func printPersonInfo(p person) {
fmt.Printf("name is %v\n", p.sayName())
fmt.Printf("age is %v\n", p.sayAge())
}
This function is defined printPersonInfo
, it receives an person
interface type of the parameter, and then print out the person
interface sayName()
string returned by the method, sayAge()
the method returns Age
printPersonInfo
The advantage of this function is that it is oriented programming interface, as long as a type implements Stringer
the interface, can print out a corresponding character string, and do not control the specific type implementations.
Since student
implements person
the interface, so variable stu
as a function of printPersonInfo
the parameters, may be printed in the following manner:
printPersonInfo(stu)
Output
name is wohu
age is 20
Let structure teacher
also implement person
an interface, as shown in the following code:
type teacher struct {
name string
age int
}
func (t teacher) sayName() string {
return t.name
}
func (t teacher) sayAge() int {
return t.age
}
Since the structure teacher
also implements the person
interface, printPersonInfo
function without any change, it can be directly used, as follows:
printPersonInfo(t)
Output result:
name is Jack
age is 40
This is the benefit of interface-oriented, as long as the definition and caller meet the agreement, you can use it, regardless of the specific implementation. Implementers of the interface can also upgrade and refactor better without any impact, because the interface convention has not changed.
5. Value receiver and pointer receiver
We already know that if you want to implement an interface, you must implement all the methods provided by the interface, and when explaining the method in the last lesson, you define a method, which has two types: value type receiver and pointer type receiver. Both methods can be invoked, because the Go
compiler automatically do the conversion, the value of type pointer and type of recipient receivers are equivalent. But in the implementation of the interface, the receiver of the value type and the receiver of the pointer type are different. I will analyze the difference between the two in detail below.
The above has been verified structure type implements person
an interface, then the structure corresponding to the pointer is also implements this interface it? I used the following code to test:
printPersonInfo(&s)
Output result:
name is wohu
age is 20
After testing will find the variable t
pointer as an argument passed to printPersonInfo
the function are possible, compile and run are normal. This proves that when a value type receiver implements an interface, both the type itself and the pointer type of the type implement the interface.
Example recipient median ( s student
) implements person
the interface, the type student
and pointer type it *student
would have achieved person
the interface.
Now, I change the receiver to a pointer type, as shown in the following code:
func (s *student) sayName() string {
return s.name
}
func (s *student) sayAge() int {
return s.age
}
Pointer type receiver modified to find example line printPersonInfo(stu)
code compilation is not passed, suggesting the following errors:
demo.go:46:17: cannot use stu (type student) as type person in argument to printPersonInfo:
student does not implement person (sayAge method has pointer receiver)
Meaning that the type student
does not implement person
the interface. This proves that when a pointer type receiver implements an interface, only the corresponding pointer type is considered to implement the interface.
to sum up:
-
When the value type as the recipient,
student
type and*student
type implements this interface; -
When the pointer type as the receiver, only
*student
the type implements this interface;
It can be found that there are types that implement interfaces *student
, which also shows that the pointer type is more versatile, no matter which kind of receiver, it can implement the interface.
package main
import "fmt"
type student struct {
name string
age int
}
type teacher struct {
name string
age int
}
type person interface {
sayName() string
sayAge() int
}
func (t teacher) sayName() string {
return t.name
}
func (t teacher) sayAge() int {
return t.age
}
func (s *student) sayName() string {
// fmt.Printf("name is %v\n", s.name)
return s.name
}
func (s *student) sayAge() int {
// fmt.Printf("age is %v\n", s.age)
return s.age
}
func printPersonInfo(p person) {
fmt.Printf("name is %v\n", p.sayName())
fmt.Printf("age is %v\n", p.sayAge())
}
func main() {
stu := student{
name: "wohu", age: 20}
// t := teacher{name: "Jack", age: 40}
printPersonInfo(stu)
// printPersonInfo(t)
}