methods, interfaces, and embedded types in the Go language

Source: Internet
Author: User
Tags email string

https://studygolang.com/articles/1113

Overview

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

    • Will the compiler make an error because we have two interface implementations at the same time?
    • If the compiler accepts such a definition, how does the compiler determine which implementation to use when the interface is called?

After writing some test code and reading the standard carefully, I found something interesting and felt it necessary to share it, so let's start with the way in the Go language.

Method

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

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

type User struct {  Name  string  Email string}func (u User) Notify() error

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

// User 类型的值可以调用接受者是值的方法damon := User{"AriesDevil", "[email protected]"}damon.Notify()// User 类型的指针同样可以调用接受者是值的方法alimon := &User{"A-limon", "[email protected]"}alimon.Notify()

In this example, when we use the pointer, Go adjusts and references the pointer so that the call can be executed. Note that when the recipient is not a pointer, the method operates a copy of the value of the recipient (meaning that even if you use a pointer to call a function, but the function's recipient is a value type, the function's internal operation is 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 recipient uses the pointer type:

func (u *User) Notify() error

One more call (note: When the recipient is a pointer, that is, using a value type to invoke the inside of the function is also the operation of the pointer, see: HTTP://PLAY.GOLANG.ORG/P/SYBB4XPFPH):

// User 类型的值可以调用接受者是指针的方法damon := User{"AriesDevil", "[email protected]"}damon.Notify()// User 类型的指针同样可以调用接受者是指针的方法alimon := &User{"A-limon", "[email protected]"}alimon.Notify()

If you do not know when to use the value, when should use the pointer as the recipient, you can go to see this introduction. This article also contains a community-agreed how to name the recipient.

Interface

The interface in the Go language is unique and offers an incredibly wide range of flexibility and abstraction. They specify a specific type of value and the pointer behaves in a specific way. From a language perspective, an interface is a type that specifies a set of methods that all methods are considered to be interface types.

The following defines an interface:

type Notifier interface {  Notify() error}

We define an interface called Notifier and include a Notify method. When an interface contains only one method, the suffix is added when the interface is named according to the Go language Convention -er . 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 is difficult to find an interface that contains more than two methods.

Implementing interfaces

The Go language is a special one when it comes to how we can get our types to implement interfaces. The Go language does not require an explicit implementation of the type's interface. If all the methods in an interface are implemented by our type, then we say that the type implements the interface.

Let's go on to the previous example, define a function to accept either a value or a pointer of the type that implements the interface Notifier :

func SendNotification(notify Notifier) error {  return notify.Notify()}

SendNotificationThe function calls the Notify method, which is implemented by passing in a value or pointer to the function. A function can then be used to execute any of the values that implement the interface or the specified behavior of the pointer.

Use our User type to implement the interface and pass in a User value of type to invoke the SendNotification method:

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: "[email protected]",  }  SendNotification(user)}// Output:cannot use user (type User) as type Notifier in function argument:User does not implement Notifier (Notify method has pointer receiver)

Detail 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 of an interface are based on how the recipients and interfaces of these methods are called. The following are the rules defined in the language specification, which are used to illustrate whether we have a type of value or pointer that implements the interface:

    • *Tthe set of callable methods for a type contains *T T all the set of methods that the recipient is or

This rule says that if the interface variable that 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 SendNotification the interface variable that we pass into the function is a value type.

    • Tthe set of callable methods for a type contains T all the methods that are accepted by the recipient

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

There are only two rules in the language specification, and I have drawn the rules that conform to our example through these two rules:

    • Tthe callable method set of the type does not contain *T the method that the recipient is

We happened to catch up with the rule I inferred, so the compiler would give an error. Notifymethod uses a pointer type as the recipient and we call the method by value type. The solution is also very simple, we just need User to pass in the value of the address to the SendNotification function just fine:

func main() {  user := &User{    Name:  "AriesDevil",    Email: "[email protected]",  }  SendNotification(user)}// Output:User: Sending User Email To AriesDevil<[email protected]>

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

Embedding type

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

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

type Admin struct {  User  Level  string}

We define a new type Admin and then User embed the type, noting that this is not called inheritance but called a combination. Usertype Admin has no relationship with type.

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

func main() {  admin := &Admin{    User: User{      Name:  "AriesDevil",      Email: "[email protected]",    },    Level: "master",  }  SendNotification(admin)}// OutputUser: Sending User Email To AriesDevil<[email protected]>

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

It turns out that we can Admin type a pointer to invoke the SendNotification function. Now Admin the type also User implements the interface by means of a method promoted from the embedded type.

If a Admin type contains User fields and methods of a type, what is the relationship between them in the struct?

When we embed a type, the method of this type becomes the method of the outer type, but when it is called, 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 the field name, and the embedded type exists as an internal type, we can use the following calling method:

admin.User.Notify()// OutputUser: Sending User Email To AriesDevil<[email protected]>

Detail code: Http://play.golang.org/p/0WL_5Q6mao

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

admin.Notify()// OutputUser: Sending User Email To AriesDevil<[email protected]>

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

So invoking a method from an external type Notify is essentially a method of an internal type.

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

Given a struct type S and a named T type, the method promotes such inclusion in the struct method set as specified below:

    • If you S include an anonymous field T , S and *S The method set contains the T method promotion for the recipient.

This rule says that when we embed a type, the recipient of the embedded type is the value type of the method that is promoted and can be called by the values and pointers of the external type.

    • Method *S set for a type contains *T method promotion for the recipient

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

    • If S an anonymous field is included *T , S and *S The method set contains the T *T method promoted by the recipient or

This rule says that when we embed a pointer to a type, the recipient of the embedded type is promoted as a value type or pointer type, and can be called by the value of an external type or by a pointer.

This is the only three rules in the method promotion in the language specification, and I derive a rule based on this:

    • If S an anonymous field is included T , S the set of methods does not contain *T the method promotion for the recipient.

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

Answer the question at the beginning

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

func (a *Admin) Notify() error {  log.Printf("Admin: Sending Admin Email To %s<%s>\n",      a.Name,      a.Email)  return nil}

AdminType implements an interface that displays information about an admin. When we use Admin a pointer to a type to invoke SendNotification a function, this will help us determine which interface implementation is called.

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

func main() {  admin := &Admin{    User: User{      Name:  "AriesDevil",      Email: "[email protected]",    },    Level: "master",  }  SendNotification(admin)}// OutputAdmin: Sending Admin Email To AriesDevil<[email protected]>

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

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

admin.Notify()// OutputAdmin: Sending Admin Email To AriesDevil<[email protected]>

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

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

Now we have enough evidence to answer the question:

    • Will 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 serves as the field name. An embedded type contains its own fields and methods as the inner type of the struct, and has a unique name. So we can have an internal implementation of the same interface and an external implementation.

    • If the compiler accepts such a definition, how does the compiler determine which implementation to use when the interface is called?

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

Summarize

In the Go language, methods, interfaces, and embedded types work together in a unique way. These features can help us organize structures like object-oriented and then achieve the same goal, and there are no other complex things. Using the language features discussed in this article, we can build a framework of abstraction and scalability with minimal code.

Reference Http://blog.go-china.org/26-methods-interfaces-and-embedded-types-in-golang

methods, interfaces, and embedded types in the Go language

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.