This is a creation in Article, where the information may have evolved or changed.
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public, the first time to see follow-up notes.
An interface is a convention, which is an abstract type, unlike the specific types we see, such as int, map, slice, and so on. The specific type, we can know what it is, and can know what to do with it, but the interface is not the same, the interface is abstract, it has only a set of interface methods, we do not know its internal implementation, so we do not know what the interface is, but we know what it can do with the method provided.
Abstraction is the advantage of the interface, it does not have to be tied to specific implementation details, we just need to define the interface, tell the coder what it can do, so that we can separate the specific implementation, so that the coding will be more flexible, the ability to adapt is very strong.
func main() { var b bytes.Buffer fmt.Fprint(&b,"Hello World") fmt.Println(b.String())}
The above is an example of using an interface, we first look at the fmt.Fprint
implementation of the function.
func Fprint(w io.Writer, a ...interface{}) (n int, err error) { p := newPrinter() p.doPrint(a) n, err = w.Write(p.buf) p.free() return}
From the source code above, we can see that the fmt.Fprint
first parameter of the function is io.Writer
this interface, so as long as the implementation of the specific type of the interface can be passed as a parameter to the fmt.Fprint
function, but bytes.Buffer
the implementation of the io.Writer
interface, it can be passed as a parameter to fmt.Fprint
the Function.
Internal implementation
We mentioned earlier that an interface is a type that defines the behavior, which is abstract, and the behavior of these definitions is not implemented directly by the interface, but by the user-defined type implemented by the method. If a user-defined type implements all the methods of an interface type declaration, the user-defined type implements the interface, so that the value of the user-defined type can be assigned to the value of the interface type.
func main() { var b bytes.Buffer fmt.Fprint(&b, "Hello World") var w io.Writer w = &b fmt.Println(w)}
In this example, because the bytes.Buffer
interface is implemented, we can assign a value that assigns the value io.Writer
of the w = &b
defined type to the value of the interface type.
After the assignment operation, if we call the interface method, we call the corresponding method of the Stored user-defined type, here we can call the user-defined type 实体类型
.
We can define many types, let them implement an interface, then these types can be assigned to this interface, when the interface method calls, in fact, is the corresponding 实体类型
method of the call, which is polymorphic.
func main() { var a animal var c cat a=c a.printInfo() //使用另外一个类型赋值 var d dog a=d a.printInfo()}type animal interface { printInfo()}type cat inttype dog intfunc (c cat) printInfo(){ fmt.Println("a cat")}func (d dog) printInfo(){ fmt.Println("a dog")}
The above example shows a polymorphic. We define an interface animal
, then define two types cat
and dog
implement the interface animal
. When used, the value of the type, the value of the cat
c
type dog
is d
assigned to the value of the interface animal
a
, and then a
the method executed separately printInfo
, you can see the different output.
a cata dog
We look at the layout of the interface values after the value of the interface is assigned. The value of the interface is a two-word-length data structure, the first word contains a pointer to the internal table structure, the information stored in this inner list, 实体类型
and the associated method set, and the second word contains a pointer to the stored 实体类型
value. So the value structure of the interface is actually two pointers, which can also indicate that the interface is actually a reference type.
Method set
We all know that if you want to implement an interface, you must implement all the methods provided by this interface, but when implementing the method, we can use the pointer receiver implementation, can also use the value of the receiver implementation, there is a difference between the two, we have a good analysis of the difference between the two.
func main() { var c cat //值作为参数传递 invoke(c)}//需要一个animal接口作为参数func invoke(a animal){ a.printInfo()}type animal interface { printInfo()}type cat int//值接收者实现animal接口func (c cat) printInfo(){ fmt.Println("a cat")}
Or the original example to change, add a invoke
function, the function receives an animal
interface type parameters, in the case of passing parameters, the value of the type is also cat
c
passed, the running program can execute normally. Now let's change it a little bit, using a type cat
of pointer &c
as a parameter pass.
func main() { var c cat //指针作为参数传递 invoke(&c)}
Just modify this one place, the other remains the same, we run the program, the discovery can also be performed normally. By this example, we can conclude that the interface is implemented by the entity type when the interface is implemented by the value recipient, whether it is a value of the entity type or a pointer to the entity type value .
Let's try to change the receiver to a pointer.
func main() { var c cat //值作为参数传递 invoke(c)}//需要一个animal接口作为参数func invoke(a animal){ a.printInfo()}type animal interface { printInfo()}type cat int//指针接收者实现animal接口func (c *cat) printInfo(){ fmt.Println("a cat")}
In this example, the receiver of the implementation interface is changed to a pointer, but when the parameter is passed, we still pass the value, click Run Program, the following exception prompt appears:
./main.go:10: cannot use c (type cat) as type animal in argument to invoke: cat does not implement animal (printInfo method has pointer receiver)
It has been clearly told in the hints that the cat
interface is not implemented animal
because printInfo
the method has a pointer receiver, so cat
the value of the type c
cannot be used as an interface type animal
parameter. Let's change it a little bit and pass the pointer as a parameter.
func main() { var c cat //指针作为参数传递 invoke(&c)}
The other is unchanged, just to use the parameters of the previous values, instead of using pointers as parameters, we run the program, we can run normally. This shows that when an entity type implements an interface with a pointer receiver, only pointers to that type are considered to implement the interface
Now let's summarize both of these rules, first in terms of whether the method recipient is a value or a pointer.
Methods Receivers |
Values |
(T T) |
T and *t |
(t *t) |
*t |
The table above can be interpreted as: if it is a value recipient, the value and pointer of the entity type can implement the corresponding interface, and if it is the pointer receiver, then only the type pointer can implement the corresponding interface.
Next we look at the angle of whether the entity type is a value or a pointer.
Values |
Methods Receivers |
T |
(T T) |
*t |
(T T) and (T *t) |
The above table can be read as follows: The value of a type can only implement the interface of the receiver of the value, and a pointer to a type can implement either the interface of the value receiver or the interface of the pointer receiver.
Standard library
"Go language Combat" reading notes, not to be continued, welcome to sweep code attention flysnow_org
to the public, the first time to see follow-up notes.