This is a creation in Article, where the information may have evolved or changed. Rob Paik (Rob Pike), one of the leading designers of the go language, once said that if you can only select a Go language sexually ported to other languages, he chooses the interface. Visible interface in the Golang of the status, and the Gloang of the language brought about by the vitality.
What is interface in the Golang?
An interface is equivalent to a contract that specifies a set of operations that an object can provide. To understand the concept of interfaces in Golang we'd better start by looking at how other modern languages implement interfaces. C + + does not provide a keyword such as interface, which implements an interface through a pure virtual base class, while Java declares an interface through the interface keyword. They have a common feature of a class to implement the declaration that the interface must be displayed, as follows in Java mode:
Interface IFoo { void Bar (); Class Foo implements IFoo { void Bar () {}}
This must make a clear statement that you have achieved the way an interface is We call this an intrusive interface. About the disadvantages of intrusive interfaces we are not going to discuss this in detail here, looking at Java's huge inheritance system and its cumbersome interface types we can see the twos. Golang adopted a completely different design concept, in the Go language, a class only needs to implement the interface requirements of all functions, we say that this class implements the interface, For example:
Type Iwriter Interface { Write (buf [] byte) (n int, err error)}type File struct { //...} Func (f *file) Write (buf [] byte) (n int, err error) { //...}
non-intrusive interface a very important benefit is to remove the complex inheritance system, we look at Hudashin in the "Go Language Programming" a book to make a summary: first, the Go Language standard library, no longer need to draw the class Library inheritance tree diagram. You must have seen many inheritance tree diagrams for C + +, Java, C # class libraries. Here's a Java Inheritance Tree graph: http://docs.oracle.com/javase/1.4.2/docs/api/overview-tree.html in Go, the inheritance tree of the class is meaningless, You just need to know what methods this class implements, and what each method means is enough. Second, the implementation of the class, only need to care about what they should provide, no longer tangled interface needs to be more thin to be reasonable. Interfaces are defined on demand by the consumer without prior planning. third, there is no need to import a package in order to implement an interface, because multiple references to an external package means more decoupling. The interface is defined by the consumer in terms of its own requirements, and the consumer does not have to care if other modules have defined similar interfaces. If you study the structure of Golang, students who learn C + + may find that the concept of Golang in the interface is a bit like the concept in C + +, do not know concept students can see Liu Weipeng "c++0x Ramble" Series: Concept, concept!. C + + templates to achieve this effect, no matter what type you use to instantiate, as long as the corresponding set of actions to meet the template can be instantiated normally, otherwise it will be compiled does not pass. Unlike C + + templates, which can be fully checked at compile time, Golang can only be queried at runtime for most cases, and the details of the interface query are explained later. In addition, if you have a classmate before the QT, it is easy to find another advantage of this non-invasive interface, QT, an important feature is the signal and slot, it realizes the listener and receiver decoupling, The way it is actually used is that the preprocessing of QT generates a static connection code. And if using Golang to implement this set of mechanisms is simply convenient, do not need to generate code in a way, the decoupling between listener and receiver is itself a natural manifestation of Golang.
The role of interface in Golang in object-oriented thought
Golang does not support complete object-oriented thinking, it does not inherit, polymorphism is completely dependent on the implementation of the interface. Golang can only emulate inheritance, which is essentially a combination, except that the Golang language provides us with some syntactic sugars to make it appear to have inherited effects. An important basic principle in object-oriented--the Richter substitution principle (Liskov Substitution Principle LSP) does not work here, and the students who are accustomed to object-oriented languages may be somewhat uncomfortable when you point a pointer to a parent class to the object of the subclass. Golang will throw a compile error without being stingy. Golang's design philosophy is the Boulevard to Jane, the traditional concept of inheritance in the Golang is not so necessary, golang through the interface to achieve polymorphism, below we look at an example, see how Golang is to implement the principle of dependency inversion, first look at C + + Implementation of:
struct Ipizzacooker { virtual void Prepare (pizza*) = 0; virtual void Bake (pizza*) = 0; virtual void Cut (pizza*) = 0;} struct Pizzadefaultcooker:public ipizzacooker { pizza* Cookonepizza () { pizza* p = new Pizza (); Prepare (p); Bake (p); Cut (p); return p; } virtual void Prepare (pizza*) { //....default Prepare Pizza } virtual void Bake (pizza*) { //.... Default Bake Pizza } virtual void Cut (pizza*) { //....default Cut pizza }} struct mypizzacooker:pub Lic Pizzadefaultcooker { virtual void Bake (pizza*) { //....bake Pizza use my Style }} int main () { MyP Izzacooker Cooker; pizza* p = Cooker. Cookonepizza (); //.... return 0;}
This example is simple to cook a new pizza through a pizza class, the process of cooking is implemented Cookonepizza in the parent class, and the subclass overrides the Bake method. Let's look at how this example is implemented in Golang:
Type Ipizzacooker Interface { Prepare (*pizza) Bake (*pizza) Cut (*pizza)} func Cookonepizza (IPC Ipizzacooker) *pizza { P: = new (Pizza) IPC. Prepare (p) IPC. Bake (p) IPC. Cut (P) return p} type pizzadefaultcooker struct {} func (this *pizzadefaultcooker) Cookonepizza () *pizza { return Cookonepizza (This)}func (this *pizzadefaultcooker) Prepare (*pizza) { //....default Prepare pizza}func (This * Pizzadefaultcooker) Bake (*pizza) { //....default Bake pizza}func (this *pizzadefaultcooker) Cut (*pizza) { // .... Default cut pizza} type Mypizzacooker struct { Pizzadefaultcooker} func (this *mypizzacooker) Cookonepizza () *pi Zza { return Cookonepizza (This)}func (this *mypizzacooker) Bake (*pizza) { //....bake Pizza use my style} func ma In () { var cooker mypizzacooker P: = Cooker. Cookonepizza () //....}
since Golang's polymorphism has to be achieved by means of an interface, which is actually not strictly a dependency inversion, in this case Golang seems a bit clumsy, it actually there can be a more elegant implementation of the scheme, This example is just to give you a description of how polymorphic is implemented in Golang, and the so-called simulation inheritance is not equivalent to an object-oriented inheritance relationship.
Interface Memory Layout
It is necessary to understand the memory structure of interface, and only by understanding this can we further analyze the efficiency of situations such as type assertions. Let's look at an example:
Type Stringer Interface { string () string} type Binary UInt64 func (i Binary) string () string { return StrConv. Formatuint (I.get (), 2)} func (I Binary) Get () UInt64 { return UInt64 (i)} func main () { var b Binary = : Stringer (b) FMT. Print (S.string ())}
interface actually consists of two members in memory, such as the tab pointing to a virtual table, and data pointing to the actual reference. The virtual table depicts the actual type information and the set of methods required by the interface . Observing the structure of the itable, the first is some metadata describing the type information, followed by a list of function pointers satisfying the Stringger interface (note that this is not the set of function pointers for the actual type binary). So if we make a function call through an interface, the actual operation is actually s.tab->fun[0] (s.data). Is it like the virtual table of C + +? Next we'll look at the Golang of the virtual table and the difference between the virtual table of C + +. First look at C + +, which creates a set of methods for each type, and its virtual table is actually the set of methods itself or part of it, when faced with multiple inheritance when (or when implementing multiple interfaces, which is common), there are multiple virtual table pointers in the C + + object structure, each pointing to different parts of the method set, so that the function pointers in the C + + method set are in strict order. Many C + + novice in the face of multiple inheritance becomes the egg pain chrysanthemum tight, because it's this way of design, in order to ensure that its virtual table can work properly, C + + introduced a lot of concepts, what virtual inheritance Ah, interface function The same name problem Ah, the same interface at different levels are inherited multiple problems ah and so on ... It is also easy for the veteran to write the problem code out of negligence. let's look at the implementation of Golang, like C + +, Golang Each type creates a set of methods, unlike the virtual tables of interfaces that are specifically generated at run time. Perhaps a careful classmate can find out why a virtual table is generated at run time. Because too much, the combination of each interface type and all of the entity types that satisfy its interface is the number of possible virtual tables, in fact most of them are not needed, so Golang chooses to generate it at run time, for example, when first encountered in an example
s
: = Stringer (bWhen such a statement occurs, Golang generates a stringer interface corresponding to the binary type of the virtual table and caches it. It is easy to understand the Golang memory structure, and then to analyze the efficiency of situations such as type assertions, and when determining whether a type satisfies an interface, Golang uses the set of methods required by the type to match the set of methods needed by the interface, if the set of methods of the type completely contains the set of methods of the interface. You can think of the type as satisfying the interface. For example, if a type has M methods, an interface has n methods, it is easy to know that the time complexity of this decision is O (mXn), but can be optimized in a pre-ordered manner, the actual time complexity is O (m+n).
Master Portal: Golang Technical essay
Reference documents
"Go language Programming" Xu Shiwei http://research.swtch.com/interfaces(I can't seem to open it now ...) )