The methods, interfaces, and embedded types in go language are detailed _golang

Source: Internet
Author: User
Tags anonymous email string

Overview

In the go language, what happens if a struct and an embedded field simultaneously implement the same interface? Let's guess, there are two possible problems:

1. Does the compiler make an error because we have two interface implementations at the same time?
2. If the compiler accepts such a definition, how can the compiler determine which implementation to use when the interface is invoked?

After writing some test code and reading the standard in earnest, I found something interesting and felt the need to share it, so let's start with the approach in the go language.

Method

There are also functions and methods in the go language. One method is a function that contains the recipient, which can be either a named type or a value of a struct type or a pointer. All methods of a given type belong to a set of methods of that type.

The following defines a struct type and a method of that type:

Copy Code code as follows:

Type User struct {
Name string
Email string
}

Func (U User) Notify () error

First we define a struct type called User and then define a method of that type called Notify, and the recipient of the method is a value of the user type. To invoke the Notify method we need a value or pointer of the User type:

Copy Code code as follows:

A value of the User type can invoke a method that the recipient is a value
Damon: = user{"Ariesdevil", "ariesdevil@xxoo.com"}
Damon. Notify ()

A pointer to the User type can also invoke a method where the recipient is a value
Alimon: = &user{"A-limon", "alimon@ooxx.com"}
Alimon. Notify ()

In this example, when we use a pointer, the go adjustment and reconciliation reference pointer makes the call executable. Note that when the recipient is not a pointer, the method operates a copy of the recipient's value (meaning that even if you use a pointer to call the function, but the recipient of the function is the value type, the function internal operation or the operation of the copy, not the pointer operation, see: http:// PLAY.GOLANG.ORG/P/DBHWU0P1PV).

We can modify the Notify method so that its recipients use the pointer type:

Copy Code code as follows:

Func (U *user) Notify () error

One more time before the call (note: When the recipient is the pointer, that is, the value type is invoked, then the function is also an operation on the pointer, see: HTTP://PLAY.GOLANG.ORG/P/SYBB4XPFPH):

Copy Code code as follows:

A value of the User type can invoke a method that the recipient is a pointer
Damon: = user{"Ariesdevil", "ariesdevil@xxoo.com"}
Damon. Notify ()

A pointer to the user type can also invoke a method that the recipient is a pointer
Alimon: = &user{"A-limon", "alimon@ooxx.com"}
Alimon. Notify ()

If you don't know when to use the value and when to use the pointer as the recipient, you can look at the introduction. This article also contains the name of the recipient of the Community Agreement.

Interface

The interfaces in the go language are unique and provide an incredible array of flexibility and abstraction. They specify a particular type of value and the pointer behaves in a particular way. From a language perspective, an interface is a type that specifies a set of methods, all of which are considered to be the interface type.

The following defines an interface:

Copy Code code as follows:

Type Notifier Interface {
Notify () Error
}

We define an interface called Notifier and include a Notify method. When an interface contains only one method, the-er suffix is added when naming the interface according to the convention of the Go language. This Convention is useful, especially when interfaces and methods have the same name and meaning.

We can define as many methods as possible in the interface, but in the Go Language standard library, it's hard to find an interface that contains more than two methods.

Implementing interfaces

When it comes to how we're going to get our type to implement the interface, the go language is a special one. The go language does not require us to explicitly implement type interfaces. If all the methods in an interface are implemented by our type, then we say that the type implements the interface.

Let's go ahead and define a function to accept any value or pointer to a type that implements the interface Notifier:

Copy Code code as follows:

Func sendnotification (notify Notifier) error {
return notify. Notify ()
}

The SendNotification function calls the Notify method, which is implemented as a value or pointer to the function. This allows a function to be used to perform any of the specified behaviors of the value or pointer that implements the interface.

Implement the interface with our user type and pass in a value of user type to invoke the SendNotification method:

Copy Code code as follows:

Func (U *user) Notify () error {
Log. Printf ("User:sending User Email to%s<%s>\n",
U.name,
U.email)
return Nil
}

Func Main () {
User: = user{
Name: "Ariesdevil",
Email: "Ariesdevil@xxoo.com",
}

SendNotification (user)
}

Output:
Cannot use User (type user) as type Notifier in function argument:
User does not implement Notifier (Notify method has pointer)

Detailed code: Http://play.golang.org/p/KG8-Qb7gqM

Why does the compiler not consider our value to be the type that implements the interface? The invocation rules for interfaces are based on how the recipients and interfaces of these methods are invoked. The following are the rules defined in the language specification, which are used to indicate whether one of our type values or pointers implements the interface:

1. The callable method set of type *t contains all the set of methods for which the recipient is *t or T

The rule says that if the interface variable we use to invoke a particular interface method is a pointer type, then the recipient of the method can be a value type or a pointer type. Obviously our example does not conform to the rule because the interface variable we passed in the SendNotification function is a value type.

1. The callable method set of type T contains all methods for which the recipient is T

This rule says that if the interface variable we use to invoke a particular interface method is a value type, then the recipient of the method must also be a value type for the method to be invoked. Obviously our example also does not conform to this rule, because we Notify the recipient of the method is a pointer type.

There are only two rules in the language specification, and I've come up with the rules that fit our example through these two rules:

1. The callable method set of type T does not contain a method that the recipient is *t

We happened to catch up with this rule that I inferred, so the compiler would give an error. The Notify method uses the pointer type as the recipient and we call the method through the value type. The solution is also simple, we only need to pass the User value of the address to the SendNotification function is good:

Copy Code code as follows:

Func Main () {
User: = &user{
Name: "Ariesdevil",
Email: "Ariesdevil@xxoo.com",
}

SendNotification (user)
}

Output:
User:sending User Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: Http://play.golang.org/p/kEKzyTfLjA

Embedded type

The struct body type can contain anonymous or embedded fields. Also called embedding a type. When we embed a type into a struct, the name of the type acts as the field name for the embedded field.

The following defines a new type and embeds our User type in it:

Copy Code code as follows:

Type Admin struct {
User
Level string
}

We define a new type of Admin and embed the User type, and note that this is not called inheritance but is called a combination. The User type is not related to the Admin type.

Let's change the main function, create a variable of Admin type and pass the address of the variable into the SendNotification function:

Copy Code code as follows:

Func Main () {
admin: = &admin{
user:user{
Name: "Ariesdevil",
Email: "Ariesdevil@xxoo.com",
},
Level: "Master",
}

SendNotification (Admin)
}

Output
User:sending User Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: Http://play.golang.org/p/ivzzzk78TC

It turns out that we can Admin type a pointer to call the SendNotification function. The Admin type is now also implemented through a method promoted from the embedded User type.

If the Admin type contains fields and methods for the User type, what are their relationships in the structure?

When we embed a type, the method of that type becomes the method of the outer type, but when it is invoked, the recipient of the method is the inner type (the embedded type), not the outer type. -effective Go

So the name of the embedded type acts as a field name and the embedded type exists as an intrinsic type, and we can use the following invocation method:

Copy Code code as follows:

Admin. User.notify ()

Output
User:sending User Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: HTTP://PLAY.GOLANG.ORG/P/0WL_5Q6MAO

Here we use the type name to access the fields and methods of the inner type. However, these fields and methods are also promoted to external types:

Copy Code code as follows:

Admin. Notify ()

Output
User:sending User Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: Http://play.golang.org/p/2snaaJojRo

So invoking the Notify method through an external type is essentially an internal type of method.

The following are the rules for promoting the set of internal type methods in the Go language:

Given a struct type S and a type named T, the method elevation is included in the structural body method set as follows:

1. If S contains an anonymous field t,s and *s the method set contains the method elevation of the recipient for T.

What this rule says is that when we embed a type, the recipient of the embedded type will be promoted and can be called by the value of the external type and by the pointer.

1. For *s-type method sets that contain the recipient-*t method elevation

The rule is that when we embed a type, a set of methods that can be called by a pointer to an external type only the recipient of the embedded type is a set of methods of the pointer type, that is, when an external type uses a pointer to call an internal type's method, only the recipient's internal type method set of the pointer type is promoted.

1. If S contains an anonymous field *t,s and *s's method set contains the recipient's method for T or *t elevation

What this rule says is that when we embed a pointer of a type, a method of an embedded type that is a value type or a pointer type is promoted and can be invoked by a value or pointer of an external type.

This is the only three rule in the language specification, and I derive a rule from this:

1. If S contains an anonymous field t,s the method set does not contain the *t method elevation for the recipient.

The rule is that when we embed a type, the recipient of the embedded type is a pointer to a method that cannot be accessed by the value of an external type. This is also consistent with the interface rules we have stated above.

Answer the question at the beginning

Now we can write a program to answer the two questions raised at the beginning, first we let the Admin type implement the Notifier interface:

Copy Code code as follows:

Func (a *admin) Notify () error {
Log. Printf ("Admin:sending Admin Email to%s<%s>\n",
A.name,
A.email)

return Nil
}

The admin type implements an interface that displays an admin-side message. When we use the Admin type pointer to invoke the function sendnotification, this will help us determine exactly which interface implementation is invoked.

Now create a value of Admin type and pass its address into the SendNotification function to see what happens:

Copy Code code as follows:

Func Main () {
admin: = &admin{
user:user{
Name: "Ariesdevil",
Email: "Ariesdevil@xxoo.com",
},
Level: "Master",
}

SendNotification (Admin)
}

Output
Admin:sending Admin Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: Http://play.golang.org/p/JGhFaJnGpS

As expected, the Admin type interface implementation is called by the SendNotification function. Now what happens when we call the Notify method with an external type:

Copy Code code as follows:

Admin. Notify ()

Output
Admin:sending Admin Email to Ariesdevil<ariesdevil@xxoo.com>

Detailed code: Http://play.golang.org/p/EGqK6DwBOi

We get the output of the Admin type interface implementation. The interface implementation of the User type is not promoted to an external type.

Now we have enough evidence to answer the question:

1. Does the compiler make an error because we have two interface implementations at the same time?

No, because when we use an embedded type, the type name acts as the field name. An embedded type contains its own fields and methods, and has a unique name, as the inner type of the struct body. So we can have both internal and external implementations of the same interface.

1. If the compiler accepts such a definition, how can the compiler determine which implementation to use when the interface is invoked?

If the external type contains an interface implementation that meets the requirements, it will be used. Otherwise, any inner-type interface implementation can be used directly by the external type, by means of a method elevation.

Summarize

In the Go language, methods, interfaces, and embedded types work together in a unique way. These features can help us to organize and achieve the same goals as object-oriented, and there is no other complex thing. With the language features discussed in this article, we can build abstractions and scalability frameworks with very little code.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.