In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)05/31 Report--
This article focuses on "how to use the Go interface", interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn how to use the Go interface.
Introduction to the usage of Interface
An interface (interface) is a type that defines a behavior (method).
Type Namer interface {my_method1 () my_method2 (para) my_method3 (para) return_type.}
However, these behaviors are not implemented directly on the interface, but need to be implemented in user-defined methods. Therefore, the method my_methodN in the above Namer interface type has no actual method body, but only stores the signature of these methods in the interface Namer (signature = function name + parameter (type) + return value (type)).
When a user-defined type implements these methods defined on the interface, the value of the custom type (that is, the instance) can be assigned to the value of the interface type (that is, the interface instance). This assignment process allows instances of user-defined types to be saved in the interface instance.
For example:
Package mainimport ("fmt") / / Shaper interface type type Shaper interface {Area () float64} / / Circle struct type type Circle struct {radius float64} / / Circle type implements methods in Shaper Area () func (c * Circle) Area () float64 {return 3.14 * c.radius * c.radius} / Square struct type type Square struct {length float64} / / Square types implement methods in Shaper Area () func (s * Square) Area () float64 {return s.length * s.length} func main () {/ / Circle type pointer type instance c: = new (Circle) c.radius = 2.5 / Square type value type instance s: = Square {3.2} / / Sharpe interface instance ins1 It is itself a pointer type var ins1 Shaper / / assigns Circle instance c to interface instance ins1 / / then instance c ins1 = c fmt.Println (ins1) / / uses type inference to assign Square instance s to interface instance ins2: = s fmt.Println (ins2)}
The output is as follows:
& {2.5} {3.2}
As can be seen from the output above, after the two interface instances ins1 and ins2 are assigned respectively, the pointer type Circle instance c and the value type Square instance s are saved respectively.
In addition, from the above assignment statements that assign ins1 and ins2:
Ins1 = cins2: = s
Does it mean that the interface instance ins is an instance of the custom type? The interface is actually a pointer type (see below for what it points to). At this time, instances c and s of custom types are called concrete instances, and ins instances are abstract instances, because the behavior (method) defined in the ins interface does not have a specific behavior pattern, while the behavior in c and s is specific.
Because the interface instance ins is also an instance of a custom type, when an instance of a custom type is saved in the interface instance, the method of the saved instance can be called directly from the interface. For example:
Fmt.Println (ins1.Area ()) / / output 19.625fmt.Println (ins2.Area ()) / / output 10.24
Here ins1.Area () calls the method Area () on the Circle type, and ins2.Area () calls the method Area () on the Square type. This shows that the interface of Go can achieve polymorphism in object-oriented: methods with the same name but different functions can be called on demand.
What is stored in the interface instance
As mentioned earlier, the interface type is a pointer type, but what exactly does it store?
The data structure of the interface type is 2 pointers, which takes up 2 machine words.
When the type instance c is assigned to the interface instance ins1, use the println () function to output ins1 and c and compare their addresses:
Println (ins1) println (c)
Output result:
(0x4ceb00re0xc042068058) 0xc042068058
As you can see from the result, the interface instance contains two addresses, the second of which is exactly the same as the address of type instance c. And the second address c is an instance of the pointer type of Circle, so the second value in ins is also a pointer.
What is the first pointer in ins? It points to an internal table structure iTable, which contains two parts: the first part is the type information of instance c, that is, * Circle, and the second part is the method set of this type (Circle), that is, all the methods of Circle type (in this example, Circle defines only one method Area ()).
So, as the figure shows:
Notice that instance c in the figure above is a pointer, a Circle instance of the pointer type.
For the Square instance of value type, the saved content is shown below:
In fact, the content saved in the interface instance is reflected incisively and vividly in reflect, and everything in reflect is inseparable from the content saved by the interface instance.
Method set (Method Set) rules
Official manual interpretation of Method Set: https://golang.org/ref/spec#Method_sets
The method set of the instance determines the interface it implements and the methods that can be called through receiver.
A method set is a collection of methods of types, and for non-interface types, each type is divided into two Method Set: an instance of a value type is a Method Set, and an instance of a pointer type is another Method Set. The two Method Set consist of methods of different receiver types:
Type of instance receiver-- value type: t (T Type) pointer type: * T (T Type) or (T * Type)
In other words:
The Method Set of an instance of a value type consists only of receiver (T Type) of the value type
The Method Set of an instance of a pointer type consists of a value type and a pointer type receiver, namely (T Type) and (T * Type).
What does this mean? From the point of view of receiver:
Type of receiver instance-(T Type) T or * T (T * Type) * T
What it means is:
A method where receiver is a pointer type can only exist in an instance method set of a pointer type
Methods that receiver is a value type exist in both the instance method set of the value type and the method set of the pointer type
From the point of view of implementing interface methods:
If the receiver of a method that implements an interface is of (T * Type) type, then only the instance of pointer type * T implements this interface, because this method is not in the instance T method set of value type.
If the receiver of a method that implements an interface is of type (T Type), then both the instance T of the value type and the instance * T of the pointer type implement this interface, because this method is in both the instance T method set of the value type and the instance * T method set of the pointer type.
For instance. Interface method Area (). When the custom type Circle has an Area () method with a receiver type of (c * Circle), it indicates that the interface method is implemented, but only when the type of the Circle instance is a pointer type, the instance is considered to have implemented the interface, can be assigned to the interface instance, and can be used as an interface parameter. As follows:
Package mainimport "fmt" / / Shaper interface type type Shaper interface {Area () float64} / / Circle struct type type Circle struct {radius float64} / / Circle type implementation method Area () / / receiver type in Shaper is pointer type func (c * Circle) Area () float64 {return 3.14 * c.radius * c.radius} func main () {/ declare 2 interface instances var ins1 Pointer type instance C1 of ins2 Shaper / / Circle: = new (Circle) c1.radius = 2.5 ins1 = C1 fmt.Println (ins1.Area ()) / / Circle value type instance c2: = Circle {3.0} / / the following will report an error ins2 = c2 fmt.Println (ins2.Area ())}
Error result:
Cannot use c2 (type Circle) as type Shaperin assignment: Circle does not implement Shaper (Area method haspointer receiver)
What it means is that instance c2 of the circle value type does not implement the Area () method of the Share interface, and its Area () method is the receiver of the pointer type. In other words, there is no Area () method in the Method Set of the c2 instance of the value type with the receiver type as a pointer.
So, it should be changed to:
Ins2 = & c2
Declare another method whose receiver is of value type. The following code is fine.
Type Square struct {length float64} / / implementation method Area () Receiver is of value type func (s Square) Area () float64 {return s.length * s.length} func main () {var ins3,ins4 Shaper / / Square instance of value type S1: = Square {3.0} ins3 = S1 fmt.Println (ins3.Area ()) / pointer Square instance S2: = new (Square) s2.length=4.0 ins4 = S2 fmt.Println (ins4.Area ())}
Therefore, from the point of view of methods defined by the struct type, if a method of this type has a receiver method of pointer type, the interface can only be implemented by using an instance of the pointer type to assign a value to the interface variable. If all methods of this type are receiver methods of value types, feel free to assign values to interface variables using instances of value types or pointer types. The following two corresponding relationships are very helpful for understanding:
Type of instance receiver-- value type: t (T Type) pointer type: * T (T Type) or (T * Type) receiver instance type-(T Type) ) T or * T (T * Type) * T
Very often, we directly use inferred type assignments (such as ins2: = c2) to assign an instance to a variable that we think is an instance of the interface, but not necessarily. Just as c2 of the above value type is assigned to ins2, this ins2 will be another copy of the data structure copied from the c2 data structure, not an interface instance, but the Area () method can also be called through ins2:
C2 = Circle {3.2} ins2: = c2fmt.Println (ins2.Area ()) / / normal execution
It can be called because there is an Area () method in the Circle type, but this is not called through the interface.
Therefore, when using an interface, you should try to use var to declare the instance of the interface type first, and then assign the instance of the type to the interface instance (such as var ins1,ins2 Shaper), or use ins1: = Shaper (C1). In this way, an error will be reported if the type instance assigned to the interface instance does not implement the interface.
But why restrict that the receiver of the pointer type can only be the Method Set of an instance of the pointer type?
Looking at the figure below, if the receiver of the pointer type can make up the Method Set of the value type instance, then the second pointer of the interface instance must find the address of the value type instance. But in fact, not all instances of value types can get their addresses.
Which instances of value types cannot find an address? The most common are alias types of simple data types, and if their instances are generated anonymously, their address will be completely hidden by Go, and the address of the instance cannot be found by the outside world.
For example:
Package mainimport "fmt" type myint intfunc (m * myint) add () myint {return * m + 1} func main () {fmt.Println (myint (3). Add ())}
The following is the error message: the address of myint (3) cannot be found
Abc\ abc.go:11:22: cannot call pointer method on myint (3) abc\ abc.go:11:22: cannot take the address of myint (3)
Here myint (3) is an anonymous myint instance, and its underlying is that the address of the simple data type int,myint (3) is completely hidden, providing only its value object 3.
The difference between the common method and the method of implementing the interface
For ordinary methods, both instances of value type and pointer type can be called normally, and what is copied when called is determined by the type of receiver.
Func (T Type) method1 / / value type receiverfunc (T * Type) method2 / / pointer type receiver
The receiver of the pointer type determines that both the value type and the instance of the pointer type copy the pointer of the instance. The receiver of the value type determines that the instance itself is copied whether it is an instance of a value type or a pointer type.
So, for person data structures:
Type person struct {} p1: = person {} / / instance of value type p2: = new (person) / / instance of pointer type
Both p1.method1 () and p2.method1 () copy the entire person instance, but Go treats p2.method1 () with one more "step": dereferencing it. So p2.method1 () is equivalent to (* p2) .method1 ().
Both p1.method2 () and p2.method2 () copy the pointer to the person instance, except that Go has one more "step" when dealing with p1.method2 (): creating an additional reference. Therefore, p1.method2 () is equivalent to (& p1) .method2 ().
When a type implements an interface method, the method set rule determines whether the type instance implements the interface.
Type of receiver instance-(T Type) T or * T (T * Type) * T
For interface abc, interface methods method1 (), method2 (), and structure person:
Type abc interface {method1 method2} type person struct {} func (T person) method1 / / value type receiverfunc (T * person) method2 / / pointer type receiverp1: = abc (person) / / API variable save value type instance p2: = abc (& person) / / Interface variable saves pointer type instance
P2.method1 (), p2.method2 (), and p1.method1 () are all allowed, and the method of a specific person instance is called through the interface instance.
But p1.method2 () is wrong because the receiver of method2 () is of pointer type, resulting in p1 not implementing the method2 () method of interface abc.
Interface type as parameter
It is common to take the interface type as a parameter. At this point, those instances that implement the interface can be passed to the function / method as interface type parameters.
For example, the following myArea () function takes an argument of n Shaper, which is the interface type.
Package mainimport ("fmt") / / Shaper interface type type Shaper interface {Area () float64} / / Circle struct type type Circle struct {radius float64} / / Circle type implements method Area () func (c * Circle) Area () float64 {return 3.14 * c.radius * c.radius} func main () {/ / Circle pointer type instance C1: = new ( Circle) c1.radius = 2.5 myArea (C1)} func myArea (n Shaper) {fmt.Println (n.Area ())}
The above myArea (C1) passes C1 to n as an interface type parameter, and then calls c1.Area (), which calls Circle's Area () because the interface method is implemented.
If the receiver that implements the interface method is a pointer type, but it is an instance of a value type, it cannot be passed to the function as an interface parameter. As explained earlier, an instance of this type does not implement the interface.
Taking an interface as a parameter to a method or function makes everything flexible and universal, and can be called as long as it is a type instance that implements the interface.
A lot of fmt.Println () is used, and its parameter is also the interface, and it is a longer interface parameter:
$go doc fmt Printlnfunc Println (a... interface {}) (n int, err error)
Each parameter is put into a Slice called a, and the element in Slice is an interface type and an empty interface, so anything can be thrown into fmt.Println () without implementing any method. As for how everything is output, it depends on the situation: it is determined by the String () method of the type's implementation.
Nesting of interface types
Interfaces can be nested, nested internal interfaces will belong to the external interface, and the methods of the internal interface will also belong to the external interface.
For example, the ReadWrite interface and the Lock interface are nested inside the File interface.
Type ReadWrite interface {Read (b Buffer) bool Write (b Buffer) bool} type Lock interface {Lock () Unlock ()} type File interface {ReadWrite Lock Close ()}
In addition, when types are nested, if the internal type implements the interface, the external type automatically implements the interface, because the internal property belongs to the external property.
At this point, I believe you have a deeper understanding of "how to use the Go interface". You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.