Interface of Go language foundation

Keywords: Go Programming Java

The interface defines the behavior specification of an object. The interface only defines that the specification is not implemented, and the specific object implements the details of the specification.

1.1 interface type

In Go language, interface is a type, an abstract type.
interface is a set of method s, which is an embodiment of duck type programming.
The interface is like defining a protocol (rule). As long as a machine has the function of washing and drying, it is a washing machine. Don't care about attributes (data), only about behaviors (Methods).
In Java, there is also the concept of interface.

1.2 why to use interface

package main

import "fmt"

type Cat struct {}

func (c Cat) say() string  {
    return "cat"
}
type Dog struct {}

func (d Dog) say() string {
    return "Wang Wang Wang"
}
func main()  {
    var c Cat
    fmt.Println("Cat:",c.say())

    var d Dog
    fmt.Println("Dog:",d.say())
}

//Result:
//Cat: meow, meow, meow
//Dog: bark

Process finished with exit code 0
The above code defines cat and dog, both of which will bark. You will find that there is obvious code duplication in the main function. If there are more animals, there will be more say() functions. How to optimize?
Interface can be used!

1.3 definition of interface

Go language advocates interface oriented programming.
Each interface consists of several methods. The definition format of the interface is as follows:

Type interface type name interface{
    Method name 1 (parameter list 1) returns value list 1
    Method name 2 (parameter list 2) return value list 2
    ...
}

Among them:
Interface name: use type to define an interface as a custom type name.
    When the interface of Go language is named, er is usually added after the word. For example, the interface with write operation is called Writer, and the interface with string function is called Stringer.
    The interface name should highlight the type meaning of the interface.
Method name: when the initial of the method name is uppercase and the initial of the interface type is uppercase, the method can be accessed by code other than the package where the interface is located.
Parameter list, return value list: parameter variable names in parameter list and return value list can be omitted.

For example:
type writer interface{
    Write([]byte) error
}

When i see the value of this interface type, i don't know what it is. The only thing i know is to do something through its Writer method.

1.4 conditions for interface implementation

As long as an object implements all the methods in the interface, it implements the interface. That is, the interface is a list of methods to be implemented.
package main

import "fmt"

//Define a Sayer interface
type Sayer interface {
    say()
}

//Define two structures: dog and cat
type dog struct {}
type cat struct {}
//Because there is only one say method in Sayer interface, we only need to implement say() method for dog and cat respectively to implement Sayer interface.
func (d dog) say()  {
    fmt.Println("Wang Wang Wang")
}
func (c cat) say()  {
    fmt.Println("cat")
}
//Interface implementation is like this. As long as all the methods in the interface are implemented, the interface will be implemented.
func main()  {
    var d dog
    var c cat
    d.say()
    c.say()
}

//Result:
//Wang Wang Wang
//cat

Process finished with exit code 0

1.5 interface type variables

So what's the use of implementing an interface?
The interface type variable can store all instances that implement the interface.
For example, in the example above, variables of type Sayer can store variables of type dog and cat.
package main

import "fmt"

//Define a Sayer interface
type Sayer interface {
    say()
}

//Define two structures: dog and cat
type dog struct {}
type cat struct {}
//Because there is only one say method in Sayer interface, we only need to implement say() method for dog and cat respectively to implement Sayer interface.
func (d dog) say()  {
    fmt.Println("Wang Wang Wang")
}
func (c cat) say()  {
    fmt.Println("cat")
}
//Interface implementation is like this. As long as all the methods in the interface are implemented, the interface will be implemented.
func main()  {
    var x Sayer //Declare a variable x of type Sayer
    c := cat{}  //Instantiate a cat
    d := dog{}  //Instantiate a dog
    x = c       //You can assign the cat sample directly to x
    x.say()     //cat
    x = d       //You can assign the power of dog directly to x
    x.say()     //Wang Wang Wang
}

//Result:
//cat
//Wang Wang Wang

Process finished with exit code 0

1.6 difference between the implementation interface of value receiver and pointer receiver

What's the difference between using a value receiver to implement an interface and a pointer receiver to implement an interface? Take a look at the following example

Value receiver implementation interface

package main

import "fmt"

type Mover interface {
    move()
}
type dog struct {}
//Value receiver implementation interface
func (d dog) move()  {
    fmt.Println("Dogs can move!")
}
func main()  {
    var x Mover
    var wangcai = dog{} //Wangcai is a dog type
    x = wangcai         //x can receive dog type
    x.move()

    var fugui = &dog{}  //Wealth is the type of * dog
    x = fugui           //x can receive * dog type
    x.move()
}

//Result:
//Dogs can move!
//Dogs can move!

Process finished with exit code 0
From the above code, we can see that when using the value receiver to implement the interface, whether it is a dog structure or a variable of the structure pointer * dog type, it can be assigned to the modified interface variable.
Because there is a syntax sugar for evaluating pointer type variables in Go language, the internal evaluation of dog pointer fugui will be automatic.

Pointer receiver implementation interface

package main

import "fmt"

type Mover interface {
    move()
}
type dog struct {}
//Value receiver implementation interface
func (d *dog) move()  {
    fmt.Println("Dogs can move!")
}
func main()  {
    var x Mover
    var wangcai = dog{} //Wangcai is a dog type
    x = wangcai         //x can't receive the dog type and directly report an error
    x.move()

    var fugui = &dog{}  //Wealth is the type of * dog
    x = fugui           //x can receive * dog type
    x.move()
}
At this time, the Mover interface is implemented by * dog type, so it is not allowed to pass in wangcai of dog type to x. at this time, x can only store the value of * dog type.

Interview questions

First of all, please observe the following code, and then answer whether this code can be compiled?

type People interface {
    Speak(string) string
}

type Student struct{}

func (stu *Student) Speak(think string) (talk string) {
    if think == "sb" {
        talk = "You are a handsome man"
    } else {
        talk = "Hello"
    }
    return
}

func main() { 
    var peo People = Student{}  //Can't be compiled. It will change to var PEO people = & student {}
    think := "Reflection"
    fmt.Println(peo.Speak(think))
}

1.7 relationship between type and interface

1.7.1 one type implements multiple interfaces

A type can implement multiple interfaces at the same time, and the interfaces are independent of each other and do not know each other's implementation.
For example, a dog can bark or move. We can define Sayer interface and Mover interface respectively.
package main

import "fmt"

type Mover interface {
    move()
}
type Sayer interface {
    say()
}
type dog struct {
    name string
}
//Implement Mover interface
func (d dog) move()  {
    fmt.Printf("%s Dogs can move!\n",d.name)
}
//Implement Sayer interface
func (d dog) say()  {
    fmt.Printf("%s Dogs barking!\n",d.name)
}
func main()  {
    var x Sayer
    var y Mover

    //dog can implement either Sayer interface or Mover interface
    var a = dog{name:"Prosperous wealth"}
    x = a
    y = a
    x.say()
    y.move()
}

//Result:
//Wangcai can bark!
//Wangcai can move!

Process finished with exit code 0

1.7.2 multiple types implement the same interface

package main

import "fmt"
//Different types in Go language can implement the same interface. First, define a Mover interface
type Mover interface {
    move()
}

type dog struct {
    name string
}
type car struct {
    brand string
}
//Implementing Mover interface with dog
func (d dog) move()  {
    fmt.Printf("%s Dogs can move!\n",d.name)
}
//car implements Mover interface
func (c car) move()  {
    fmt.Printf("%s The car will run!\n",c.brand)
}
//At this time, you can treat the dog and car as a moving object in the code. You don't need to pay attention to what they are, just call their move method.
func main()  {
    var x Mover

    //dog can implement either Sayer interface or Mover interface
    var a = dog{name:"Prosperous wealth"}
    var b = car{brand:"BMW"}
    x = a
    x.move()
    x = b
    x.move()
}

//Result:
//Wangcai can move!
//BMW car can run!

Process finished with exit code 0
An interface method does not need to be fully implemented by a type. An interface method can be implemented by embedding other types or structures in the type.

package main

import "fmt"

//Washing machine interface
type WashingMachine interface {
    wash()
    dry()
}
//Dryer
type dryer struct {}
//Haier washing machine
type haier struct {
    dryer //Embedded dryer
}

//The dry() method to implement the WashingMachine interface
func (d dryer) dry()  {
    fmt.Println("Throw away")
}
//The wash() method to implement the WashingMachine interface
func (h haier) wash()  {
    fmt.Println("wash")
}
func main()  {
    var d dryer
    var h haier
    d.dry()
    h.wash()
    h.dry()

}

//Result:
//Throw away
wash
//Throw away

Process finished with exit code 0

1.8 interface nesting

New interfaces can be created by nesting between interfaces.
package main

import "fmt"

//Sayer interface
type Sayer interface {
    say()
}
//Mover interface
type Mover interface {
    move()
}

//Interface nesting
type animal interface {
    Sayer
    Mover
}
//The use of the nested interface is the same as that of the ordinary interface. Here let cat implement the animal interface:
type cat struct {
    name string
}

func (c cat) say()  {
    fmt.Println("cat")
}
func (c cat) move()  {
    fmt.Println("Cats can move.")
}
func main()  {
    var x animal
    x = cat{name:"tearful"}
    x.say()
    x.move()
}

//Result:
//cat
//Cats can move.

Process finished with exit code 0

1.9 empty interface

1.9.1 definition of empty interface

An empty interface is an interface that does not have any methods defined. So any type implements an empty interface.
Variables of empty interface type can store variables of any type.
package main

import "fmt"

func main()  {
    var x interface{}
    s := "hello vita"
    x = s
    fmt.Printf("type:%T value:%v\n",x,x)
    i := 100
    x = i
    fmt.Printf("type:%T value:%v\n",x,x)
    b := true
    x = b
    fmt.Printf("type:%T value:%v\n",x,x)
}

//Result:
type:string value:hello vita
type:int value:100
type:bool value:true

Process finished with exit code 0

1.9.2 application of empty interface

Empty interface as parameter of function

A null interface implementation can receive any type of function parameter.

package main

import "fmt"

func show(x interface{})  {
    fmt.Printf("type:%T value:%v\n",x,x)
}
func main()  {
    show("hello vita")
    show(100)
    show(true)
}

//Result:
type:string value:hello vita
type:int value:100
type:bool value:true

Process finished with exit code 0

Empty interface as map value

Using an empty interface, you can map Of value Is any value.

package main

import "fmt"

func main()  {
    var studentInfo = make(map[string]interface{})
    studentInfo["name"] = "vita"
    studentInfo["age"] = 18
    studentInfo["married"] = true
    fmt.Println(studentInfo)
}

//Result:
map[age:18 married:true name:vita]

Process finished with exit code 0

1.10 type assertion

1.10.1 interface value

An empty interface can store any type of value, so how can we get the specific data it stores?

Interface value:
The value of an interface (called interface value for short) is composed of two parts: concrete type and concrete type value. These two parts are called "dynamic type" and "dynamic value" of an interface respectively.

Here's an example:
var w io.Writer
w = os.Stdout
w = new(bytes.Buffer)
w = nil

1.10.2 asserts

To determine the value in an empty interface, you can use type assertion. The syntax format is:
x.(T)
Among them:
x: Represents a variable of type interface {}
T: Indicates that the assertion x may be of type
 This syntax returns two parameters. The first parameter is the variable after x is converted to T type, and the second value is a Boolean value. If it is true, it means the assertion is successful, and if it is false, it means the assertion is failed.
package main

import "fmt"

func main()  {
    var x interface{}
    x = "hello vita"
    v,ok := x.(string)
    if ok{
        fmt.Println(v)
    }else{
        fmt.Println("Type is not string")
    }
}

//Result:
hello vita

Process finished with exit code 0
In the above example, if you want to assert multiple times, you need to write multiple if Judge. We can use it at this time switch Statement to implement:

package main

import "fmt"

func main()  {
    var x interface{}
    x= "hello"
    switch v := x.(type) {
    case string:
        fmt.Printf("x yes string Type, value is %v\n",v)
    case int:
        fmt.Printf("x yes int Type, value is %v\n",v)
    case bool:
        fmt.Printf("x yes bool Type, value is %v\n",v)
    }
}

//Result:
x yes string Type, value is hello

Process finished with exit code 0
Because an empty interface can store any type of value, it is widely used in Go language.
As for the interface, it should be noted that we need to define the interface only when there are two or more concrete types that must call the same method.
Do not write the interface for the sake of the interface, only write when necessary, to avoid unnecessary memory space waste.

Posted by kjharve on Thu, 06 Feb 2020 01:31:18 -0800