This is the 29th day of my participation in the August Wenwen Challenge.More challenges in August

Go language is interface oriented programming.

Go has only encapsulation, no inheritance and no polymorphism. So how do inheritance and polymorphism work in GO? Through the interface

1. Interface definition

An interface definition consists of two parts. Users and implementers.

What does it mean that the interface is defined by the user?

Let’s say I want to download a resource. I define a Download method. This method is defined by who uses whom.

func download(r Retriever) string {
    return r.Get("http://www.baidu.com")
}
Copy the code

A parameter r Retriever is passed to the method. This parameter can be understood as a generic in Java. We define it as an interface. And then whoever uses it will make it happen. But his overall approach is to call Get in the interface

Let’s define an interface

type Retriever interface {
    Get(s string) string
}
Copy the code

That’s the definition of an interface. Methods inside interfaces don’t have to write func

Then let’s call this interface and try it out

func main() {
    var r Retriever
    fmt.Println(download(r))
}
Copy the code

When the user calls, it simply calls down. This will return an exception because r is a null pointer

2. Interface implementation

Next we create a new package mock and write an implementation of the interface.

package mock

type Retriever struct {
    Contents string
}

func (r Retriever) Get(c string) string{
    return r.Contents
}
Copy the code

That’s the implementation of the Retriever. The Retriever here has the same name as the interface. They are in different bags. The Get method is then implemented. This completes one implementation of the Retriever interface.

Strangely, unlike Java, there are no implementation keys, and there are no interface keys.

Note: The interface implementation in GO is considered to be an implementation of the interface as long as the method name, method parameters, and return values defined by the interface are the same. This is automatically recognized in the development tools

Let’s write the implementation class again

func main() {
    var r Retriever
    r = mock.Retriever{"this is a fake www.baidu.com"} 
    fmt.Println(download(r))
}
Copy the code

When initialized, it is the initialized interface. When called, it is the implementation class

This is a mock download method that returns the following value

Let’s write another implementation class, the actual download method. For example, we download the homepage of Baidu. www.baidu.com

First create a real folder, then create a new file real

package real import ( "net/http" "net/http/httputil" "time" ) type Real struct { url string downTime time.Duration } func (r Real) Get(url string) string { resp, err := http.Get(url) if err ! = nil { panic(err) } result, err := httputil.DumpResponse(resp, true) if err ! = nil { panic(err) } resp.Body.Close() return string(result) }Copy the code

Defines a method Get(URL String) String. Go considers a structure to implement the Retriever interface as long as it defines the Get method and the input and output parameters match the interface definition

Let’s look at the actual invocation

func main() {
    var r Retriever
    r = mock.Retriever{"this is a fake www.baidu.com"}
    fmt.Println(download(r))

    r = real.Real{}
    fmt .Println(download(r)) 
}
Copy the code

This calls the second implementation of the interface, real.real

 

Question: the r variable is assigned twice, so what type is it?

3. How does the interface implement value passing and pointer passing

Func (r Real) Get(URL String) String uses pass-only modeCopy the code

All of the above methods use value passing, so if an object is large and we don’t want to use value passing, we can also use pointer passing.

Func (r *Real) Get(URL string) String uses a pointer to passCopy the code

So how does the recipient receive it? You pass in Pointers. So when we receive, we receive an address

func main() {
    var r Retriever
    r = mock.Retriever{"this is a fake www.baidu.com"}
    fmt.Println(download(r))

    r = &real2.Real{"google", 100 } 
    fmt.Println(download(r))
}
Copy the code

Otherwise, an exception will be reported.

Conclusion: When we define the get method, we pass a value (r Real), so this object is passed as a value copy. If the previously passed value is (r *Real), the structure is passed as an address copy

4. Check the interface type

  • Method 1: print FMT.Printf(“%T %v \n”, r, r)
  • Method 2: Through the Type switch
  • Method 3: Use Type Assertion

Method 1: print FMT.Printf(“%T %v \n”, r, r)

func main() {
    var r Retriever
    r = mock.Retriever{"this is a fake www.baidu.com"}
    fmt.Printf("%T, %v \n", r, r) fmt.Println(download(r))

    r = real2.Real{}
    fmt.Printf("%T, %v", r, r) //fmt.Println(download(r))
}
Copy the code

The results are as follows:

mock.Retriever, {this is a fake www.baidu.com} 
this is a fake www.baidu.com
real.Real, { 0}
Copy the code

 

Method 2: Run the Type switch

func main() { var r Retriever r = mock.Retriever{"this is a fake www.baidu.com"} judgeType(r) fmt.Println(download(r)) r  = &real2.Real{"google", 100} judgeType(r) //fmt.Println(download(r)) } func judgeType(r Retriever) { switch r.(type) { case mock.Retriever: fmt.Println("content:", r.(mock.Retriever).Contents) case *real2.Real: fmt.Println("ua:", r.(*real2.Real).Ua) } }Copy the code

Method 3: Pass Type Asserttion

Type Asserttion is type conversion.

func main() { var r Retriever r = mock.Retriever{"this is a fake www.baidu.com"} judgeType(r) fmt.Println(download(r)) r  = &real2.Real{"google", 100} judgeType(r) realRetriever : If rr, ok := r.(* real2.real) fpt.println (realRetriever) // The conversion may fail. Use another parameter, ok, to determine if rr, ok := r.(real.real); ok { fmt.Println(rr) } //fmt.Println(download(r)) }Copy the code
R.(*real2.Real) Type assertion. It can also be used to determine types. But he may fail to convert. We can use it as follows:Copy the code
if rr, ok := r.(mock.Retriever); ok {
        fmt.Println(rr)
 }
Copy the code

So these are the three ways you can type an object.

Interfaces are not just references. There are two things in the belly of an interface: a type and a value

Conclusion:

What does an interface variable contain?

  1. The type of implementer

  2. Implementor’s value or address pointer, and implementor’s pointer ultimately points to the implementor’s value

or

 

Third: Pointer receiver implementations can only be used as Pointers; Value receivers are ok. When implementing an interface method, the receiver is a pointer type, so the structure can only be built as a pointer. But if the receiver is passed by value, then the structure can receive using a pointer or a value

Such as:

package mock

type Retriever struct {
    Contents string
}

func  (r Retriever)  Get(c string) string{
    return r.Contents
}
Copy the code

This is a value receiver.

It can be used like this:

func main() {
    var r Retriever
    r = mock.Retriever{"this is a fake www.baidu.com"}
    r =  &mock.Retriever{"this is a fake www.baidu.com"}
}
Copy the code

If the receiver is a pointer, the call can only be made using a pointer call

package real import ( "net/http" "net/http/httputil" "time" ) type Real struct { Ua string TimeOut time.Duration } func (r *Real) Get(url string) string { resp, err := http.Get(url) if err ! = nil { panic(err) } result, err := httputil.DumpResponse(resp, true) if err ! = nil { panic(err) } resp.Body.Close() return string(result) }Copy the code
func main() {
    var r Retriever    
    r =  &real2.Real{"google", 100}    
}
Copy the code

content

Post func post(p Poster) {p.post ("http://www.baidu.com", map[string]string{"contents":" contents", "name":"aaa", }) }Copy the code

Then we can define an interface. Poster. This is the reverse thinking, what does the user need to use, and then write the interface according to the demand

Poster type Poster interface {Post(URL string, from map[string]string) string}Copy the code

Up to this point, download is defined the same way.

Let’s give the POST interface an implementation that implements the POST in the mock.Retriever structure

func (r *Retriever) Post(url string,
    from map[string]string) string {
    r.Contents = from["contents"]
    return "ok"
}
Copy the code

In this case, the mock.Retriever structure implements both interfaces. The Get method implements the Retriever interface, and the Post implements the Poster interface.

So we say that the interface is defined by the user. So the user also needs, and that is, I want to be able to upload as well as download. Let’s say I have a session.

There is already an upload interface, there is also a download interface, so this time to upload skills can also download, how to do? You can’t just rewrite it. How do we do that in Java? Write another interface to implement the upload and download interfaces.

In GO, we’re going to use a combination of interfaces.

// Then define a session, RetrieverPoster interface {// Add one or more of the following functions to the template: You may need to define a new interface to upload or download data. map[string]string{ "contents": "another fake a address", }) return r.Get("http://www.baidu.com") }Copy the code

then

Func main() {retriever: = &mock. retriever {" content "} fmt.println (session(retriever))}Copy the code

When called, the mock.Retriever{} structure I defined can be used directly as the RetrieverPoster type

When a retriever is passed to the session as an argument, the compiler knows that the retriever is a variable of the structure mock. retriever, which implements the Get and Post methods

So you can pass the retriever directly to the session as a parameter

7. Application of combined interface in GO SDK

For example, ReadWrite related interfaces

There are four interfaces associated with ReadWrite. These are both readable and written descriptions of their abilities. How do they do that

 

 

 

 

Above: is the way of interface combination

 

Here is the complete code

  1. The interface definition
package main import ( "aaa/retriever/mock" real2 "aaa/retriever/real" "fmt" ) // 1. Define an interface type Retriever Interface {Get(s string) string} func Download (r Retriever) string {return r.Get("http://www.baidu.com") } func main() { var r Retriever r = mock.Retriever{"this is a fake www.baidu.com"} fmt.Println(download(r)) r = real2.Real{} fmt.Println(download(r)) }Copy the code
  1. The first structure in the mock that implements the interface
package mock

type Retriever struct {
    Contents string
}

func (r Retriever) Get(c string) string{
    return r.Contents
}
Copy the code
  1. The second structure in REAL that implements the interface
package real import ( "net/http" "net/http/httputil" "time" ) type Real struct { url string downTime time.Duration } func (r Real) Get(url string) string { resp, err := http.Get(url) if err ! = nil { panic(err) } result, err := httputil.DumpResponse(resp, true) if err ! = nil { panic(err) } resp.Body.Close() return string(result) }Copy the code

5. Any type is represented by interface{}.

6. Interface combination

We have a download method up here. There’s another way to upload. How do I write that? It is the same as download. Upload Contains the URL and content to be uploaded

Post func post(p Poster) {p.post ("http://www.baidu.com", map[string]string{"contents":" contents", "name":"aaa", }) }Copy the code

Then we can define an interface. Poster. This is the reverse thinking, what does the user need to use, and then write the interface according to the demand

Poster type Poster interface {Post(URL string, from map[string]string) string}Copy the code

Up to this point, download is defined the same way.

Let’s give the POST interface an implementation that implements the POST in the mock.Retriever structure

func (r *Retriever) Post(url string,
    from map[string]string) string {
    r.Contents = from["contents"]
    return "ok"
}
Copy the code

In this case, the mock.Retriever structure implements both interfaces. The Get method implements the Retriever interface, and the Post implements the Poster interface.

So we say that the interface is defined by the user. So the user also needs, and that is, I want to be able to upload as well as download. Let’s say I have a session.

There is already an upload interface, there is also a download interface, so this time to upload skills can also download, how to do? You can’t just rewrite it. How do we do that in Java? Write another interface to implement the upload and download interfaces.

In GO, we’re going to use a combination of interfaces.

// Then define a session, RetrieverPoster interface {// Add one or more of the following functions to the template: You may need to define a new interface to upload or download data. map[string]string{ "contents": "another fake a address", }) return r.Get("http://www.baidu.com") }Copy the code

then

Func main() {retriever: = &mock. retriever {" content "} fmt.println (session(retriever))}Copy the code

When called, the mock.Retriever{} structure I defined can be used directly as the RetrieverPoster type

When a retriever is passed to the session as an argument, the compiler knows that the retriever is a variable of the structure mock. retriever, which implements the Get and Post methods

So you can pass the retriever directly to the session as a parameter

7. Application of combined interface in GO SDK

For example, ReadWrite related interfaces

 

There are four interfaces associated with ReadWrite. These are both readable and written descriptions of their abilities. How do they do that

 

 

 

 

 

Above: is the way of interface combination

 

Here is the complete code

  1. The interface definition
package main import ( "aaa/retriever/mock" real2 "aaa/retriever/real" "fmt" ) // 1. Define an interface type Retriever Interface {Get(s string) string} func Download (r Retriever) string {return r.Get("http://www.baidu.com") } func main() { var r Retriever r = mock.Retriever{"this is a fake www.baidu.com"} fmt.Println(download(r)) r = real2.Real{} fmt.Println(download(r)) }Copy the code
  1. The first structure in the mock that implements the interface
package mock

type Retriever struct {
    Contents string
}

func (r Retriever) Get(c string) string{
    return r.Contents
}
Copy the code
  1. The second structure in REAL that implements the interface
package real import ( "net/http" "net/http/httputil" "time" ) type Real struct { url string downTime time.Duration } func (r Real) Get(url string) string { resp, err := http.Get(url) if err ! = nil { panic(err) } result, err := httputil.DumpResponse(resp, true) if err ! = nil { panic(err) } resp.Body.Close() return string(result) }Copy the code