Interface type variable

Go is a strongly typed language, and you cannot assign integer values to floating-point variables. Similarly, you cannot assign a type value that does not implement an interface to an interface type variable.

// 1. Define the variable as the interface type
var w io.Writer
// 2. Assign a value of a concrete type to the variable, requiring that the concrete type implements all the methods of the interface
w = os.Stdout
w = new(bytes.Buffer)
w = time.Second         // compile error: time.duration does not exist

var rwc io.ReadWriteCloser
rwc = os.Stdout
rwc = new(bytes.Buffer)  // compile error: *bytes.Buffer lacks Close method


// The right side of the equation is the interface type
w = rwc
rwc = w     // compile error: io.Writer lacks Close method
Copy the code

The rule about a type holding a method

  • Method where a value of type T does not hold a *T pointer
  • * The value of a T pointer holds a method of type T

So there may be cases where a *T pointer value can be assigned to an interface type variable and a value of type T cannot

type myWriter struct {}

func (m *myWriter) Write(p []byte) (n int, err error) {
    return
}

func main(a) {
    var w io.Writer
    w = myWriter{}      // compile error: Cannot use 'myWriter{}' (type myWriter) as the type io.Writer Type does not implement 'io.Writer' as the 'Write' method has a pointer receiver
    w = &myWriter{}     // OK
}
Copy the code

An interface type encapsulates and hides a concrete type and its value

An interface variable limits itself to calling only methods declared by the interface type, even if the variable is assigned a value that would otherwise have other methods and member variables

type myWriter struct {
    scope string
}

func (m *myWriter) Write(p []byte) (n int, err error) {
    return
}

func (m *myWriter) Func(a) {
	return
}

func main(a) {
    my := &myWriter{"cn"}
    fmt.Println(my.scope)   // OK
    my.Func()               // Ok
    var w io.Writer
    w = my
    fmt.Println(w.scope)    // compile error: w.scope undefined
    w.Func()                // compile error: w.Func undefined
}
Copy the code

Such a restriction is like a layer of security around the argument, the function inside only know the argument is the interface type, other information is not known, and cannot be accessed.

As you can see from the previous example, large interface variables can be assigned to small interfaces, and then the small interface can only call the methods of the small interface.

Meaning of an empty interface

An empty interface (interface{}) is an interface that does not declare any methods. Because it has nothing, it can be anything.

package main

import (
	"bytes"
	"fmt"
)

func emptyInterfaceIsAny(a) {
    var any interface{}
    any = true
    fmt.Println(any)
    any = 12.34
    fmt.Println(any)
    any = "hello"
    fmt.Println(any)
    any = map[string]int{"one": 1}
    fmt.Println(any)
    any = new(bytes.Buffer)
    fmt.Println(any)
    }
Copy the code

This is useful. The fmt.Println method accepts arguments of the task type only by defining that the arguments are null interface types

package main

import "fmt"

func printlnArgsIsEmptyInterface(a) {
	fmt.Println(1."hello"And []string{"world"})  // 1 hello [world]
}
Copy the code

Define interfaces properly

An interface is an abstraction of entities that have the same properties. The definition of some of the same attributes is a matter of opinion, and the criteria for judging an abstraction as good or bad are: whether users of this type of interface are comfortable with it, and how often it is used. The examples presented are abstractions from digital cultural products such as music, movies, and books.

It is worth thinking about the Streamer abstracting from music and film

type Streamer interface {
    Stream() (io.ReadCloser, error)
    RunningTime() time.Duration
    Format() string
}
Copy the code

Each concrete type implicitly implements the interface based on all the methods that they implement the interface declaration. In Go, we can define new abstractions or specific groups as needed, without changing the definition of specific types.