This paper mainly introduces the concept and use of interface in Go language. If there is any wrong or unreasonable description in the article, please leave a message. I will check and correct it in time every day.

concept

  • Represents a “protocol” or “convention” and is a collection of method declarations
  • Interfaces do not depend on types

define

  • An interface must include a method signature, which must contain the method name, parameters, and return values. Interfaces cannot have fields and cannot define their own methods.
// Animaler Indicates the Animaler interface name
type Animaler interface {
    eat(food string) string
    sleep()
}
Copy the code

Basic Application Scenarios

  • Implement polymorphic functions
package main

import (
	"fmt"
)

// Animaler interface: All compliance with this interface protocol, need to implement the speak,eat method
type Animaler interface {
	speak() string
	eat(foot string) string
}

func anmialSpeak(animaler Animaler) string {
	return animaler.speak()
}

func anmialEat(animaler Animaler, food string) string {
	return animaler.eat(food)
}

/ / Dog class
type Dog struct {
	name string
}

// Speak Dog method
func (d Dog) speak(a) string {
	return "Wang wang"
}

// Eat Dog
func (d Dog) eat(foot string) string {
	return fmt.Sprintf("%s: eat %s", d.name, foot)
}

/ / the Cat
type Cat struct {
	age int
}

// Speak Cat method
func (c Cat) speak(a) string {
	return "Meow"
}

// Eat the Cat method
func (c Cat) eat(foot string) string {
	return fmt.Sprintf("%d cat eat %s", c.age, foot)
}

func test004(a) {
	dog := Dog{name : "White"}
	cat := Cat{age: 2}
	fmt.Println(anmialSpeak(dog))  / / wang wang
	fmt.Println(anmialSpeak(cat))  / / meow meow
	fmt.Println(anmialEat(dog, "Pork"))  // Baymax: Eat pork
	fmt.Println(anmialEat(cat, "Cat food"))  // 2 Cat eat

}

func main(a) {
	test004()
}
Copy the code

Empty interface

  • If the interface does not have any method declarations, it is oneEmpty interface (interface{}), which serves a similar purpose to Object, the root type in Object, and can be assigned toAny type of object (value).
  • All types are implementedEmpty interface
  • interface{}It’s not just any type, it’s justinterface{}type

// Remember that v is not of any type, but of interface{} type; If the GO runtime needs to convert the execution type to interface{}, and all values have only one type at runtime, that is, type static.
func do(v interface{}){}func done(vals []interface{}) {
	for _, val := range vals {
		fmt.Println(val)
	}
}

func test007(a) {
	vals := []string {"conk"."pht"."nimibox"}
	Cannot use vals (type []string) as type []interface {} in argument to done
	done(vals)
}

func test008(a) {
	vals := []string {"conk"."pht"."nimibox"}
	newVals := make([]interface{}, len(vals))
	for index, v := range vals {
		newVals[index] = v
	}
	done(newVals)
}
Copy the code

Use of Pointers in interfaces

  • The interface definition does not specify whether an implementer should use onePointer receiverOr aValue of the receiverTo implement the interface
  • A pointer type can access the methods of a value type through its associated value type, but not the other way around
  • Everything in Go is passed by value. Each time a function is called, the incoming data is copied. For methods that have a value receiver, the value is copied when the method is called.

/ / Dog class
type Dog struct {
	name string
}

// Speak Dog method
func (d Dog) speak(a) string {
	return "Wang wang"
}

func (d Dog) eat(foot string) string {
	return fmt.Sprintf("%s: eat %s", d.name, foot)
}

/ / the Cat
type Cat struct {
	age int
}

// Speak Cat method
func (c *Cat) speak(a) string {
	return "Meow"
}

func (c *Cat) eat(foot string) string {
	return fmt.Sprintf("%d cat eat %s", c.age, foot)
}

// Any value of Cat may have many *Cat Pointers to it. If we try to call the *Cat method from a value of Cat, we will not know which pointer is corresponding
func test009(a) {
	Cannot use Cat literal (type Cat) as type Animaler in slice literal: Cat does not implement Animaler (eat method has pointer receiver)
	animals := []Animaler {Dog{"White"}, Cat{18}}}func test010(a) {
	// Pay attention to the details: the Dog class instantiates two objects, one pointer and one value; But the compilation is fine
	anmials := []Animaler {Dog{"White"}, &Cat{18}}, &Dog{"Black"}}
	for _, animal := range anmials {
		fmt.Println(animal.speak())
	}
}
Copy the code

Type conversion

  • Ok - the idiom mode
package main

import (
	"fmt"
)

type data int

func (d data) String(a) string {
	return fmt.Sprintf("data : %d\n", d)
}

func test001(a) {
	// Create an instance of type data
	var d data = 10
	// Create an interface instance
	var inter interface{} = d
	fmt.Printf("%T\n", inter)  // main.data

	// Determine the more specific interface type of inter: initialize to interface{} Empty interface type more specific to fmt.Stringer interface type
	if x, ok := inter.(fmt.Stringer); ok {
		fmt.Println(x) // data: 10
	}

	// Determine the original type of inter
	if y, ok := inter.(data); ok {
		fmt.Println(y) // data: 10
	}

	// panic: interface conversion: main.data is not error: missing method Error
	e := inter.(error)  // Do not use ok-idiom mode, conversion failure will cause panic
	fmt.Println(e)
}

func main(a) {
	test001()
}
Copy the code
  • Type checking
package main

import (
	"fmt"
)

// A generic interface type check function
func inspect(inter interface{}) {
	switch v := inter.(type) {
	case nil:
		fmt.Println("nil")
	case *int:
		fmt.Println(*v)
	case func(int) string:
		fmt.Println(v(100))
	case fmt.Stringer:
		fmt.Println(v)
	default:
		println("not support")}}func test002(a) {
	var inter interface{} = func(num int) string {
		return fmt.Sprintf("num: %d\n", num)
	}
	inspect(inter)
}

func main(a) {
	test002()
}
Copy the code
  • Variable length type check
// Can pass n unlimited number of arguments
func inspect(inters ...interface{}) {
	for index, inter := range(inters): {
		switch v := inter.(type) {
		case nil:
			fmt.Println("nil")
		case *int:
			fmt.Println(*v)
		case func(int) string:
			fmt.Println(v(100))
		case fmt.Stringer:
			fmt.Println(v)
		default:
			println("not support")}}}Copy the code

Interface Common pits

  • Interface variables default to nil
func test005(a) {
	var inter1, inter2 interface{}
	fmt.Println(inter1 == nil, inter1 == inter2) // true true
	inter1, inter2 = 1.1
	fmt.Println(inter1 == inter2)  // true
	inter1, inter2 = map[string]int{}, map[string]int{}
	// panic: runtime error: comparing uncomparable type map[string]int
	fmt.Println(inter1 == inter2)
}
Copy the code
  • Comparison operations
If you implement interface type support, you can do equalityCopy the code
  • Nested interface

type stringer interface {
	string(a)string
}

type tester interface {
	stringer
	test()
}

// The target type method set must have all methods including embedded interface methods to implement the interface
type person struct {}

func (p person) string(a) string {
	return "String formatting"
}

func (p person) test(a) {
	fmt.Println("Test method")}func test006(a) {
	var p person
	var t tester = p
	t.test()  / / test methods
	fmt.Println(t.string())  // String formatting
}
Copy the code

Self test

var i interface{}
i = "hello"
// What does this mean? Judging the original type of Inter, are your answers correct? ☺ ️
s := i.(string)
fmt.Println(s)  // hello

Copy the code