1. Common Usage Problems

1.1 what is var _ I = (*T)(nil)?

  • Use simple syntax to check whether T (struct) implements I (struct)
  • The left and right sides of the = can be seen separately
    • Left:var _ IEquivalent to what we normally usevar variable type
    • On the right:(* T)(nil)Is equivalent tovar variable *T nil
  • Sample code:
package main

import "fmt"

type I interface{}type I2 interface {
	say()
}

type TestStruct struct{}

func main(a) {
	var _ I = (*TestStruct)(nil)
	Var _ I2 = (*TestStruct)(nil

	// It's a long way to go
	var testStruct *TestStruct = nil
	var i I // if var I I is changed to var I I, it will not compile
	i  = testStruct // Verify that *T implements I.
	fmt.Println(i)
}
Copy the code

1.2 Golang structure and pointer implementation interface

  • When initialized to a structure pointer, it can be called regardless of whether the recipient of the implementation method is a pointer or a structure
package main

import "fmt"

type Duck interface {
	Quack()
}
type Cat struct{}

func (c Cat) Quack(a) {
	fmt.Println("meow")}//func (c *Cat) Quack() {
//	fmt.Println("meow")
/ /}

func main(a) {
	/ / structure
	var c Duck = &Cat{}
	c.Quack()

}
Copy the code
  • When initialized to a structure, it works if the recipient of the implementation method is a structure, but not if the recipient of the implementation method is a pointer
package main

import "fmt"

type Duck interface {
	Quack()
}
type Cat struct{}

// This is ok
//func (c Cat) Quack() {
//	fmt.Println("meow")
/ /}

// Not here
func (c *Cat) Quack(a) {
	fmt.Println("meow")}func main(a) {
	/ / structure
	var c Duck = Cat{}
	c.Quack()

}
Copy the code
  • Summarized as shown in figure:
  • Cause analysis,:
    • So let’s first exclude struct initializer variables, struct implementation interface and struct pointer initializer variables, struct pointer initializer variables, because they all correspond to each other, so it makes sense
    • And then we analyzeWhy do structure Pointers initialize variables and structure implementation interfaces can be called?
      • Because the compiler can get a pointer to a structure
    • In the final analysisWhy can’t a pointer implementation interface be called when a structure initializes a variable?
      • That’s because the structure can’t get the pointer that implements the interface backwards
    • The simple summary is: each pointer object can know its own type. But not every type, he knows all the Pointers to that type. Change to real life inside, A class of students (pointer) all know that they are like class flower A or class grass B (structure), but class flower A or class grass B do not know which specific students like their…..
    • It’s official:
      • All parameter passes in Golang are value passes
      • So if the receiver is Cat and the caller is a structure, we can’t extract a pointer from the structure, the compiler doesn’t create a pointer out of thin air, so it fails
      • When the receiver is Cat, if the caller is a pointer, then we can invert the type from the pointer, so it becomes the caller is a structure and the receiver is a structure

1.3 Are all Nil equal?

  • The conclusion is no. As can be seen from the following code, t1 and S1 are nil, but they are two different types that cannot be directly compared. That is to say, nil itself contains type information, otherwise the type inconsistency will not be indicated when the two nil are compared
package main

import "fmt"

type TestStruct struct{}

func main(a) {
	var t1 *TestStruct
	var s1 *string
	fmt.Println(t1) // nil
	fmt.Println(s1) // nil

	// FMT.Println(t1 == s1) // Compilation error
}
Copy the code
  • Builtin /builtin.go, prove nil it is a variable. The variable type can be pointer, channel, func, interface, map, or slice **
// nil is a predeclared identifier representing the zero value for a
// pointer, channel, func, interface, map, or slice type.
var nil Type // Type must be a pointer, channel, func, interface, map, or slice type
Copy the code

1.4 Must an empty Interface be nil?

  • The following code prints true and false, and the second false proves that even a nil interface doesn’t necessarily ==nil when printed out
  • To analyze this question, we need to know two things first:
    • The first one is nil what’s underneath? ** Refer to 1.3 ** above
    • The second thing is what is the underlying structure of the interface?
      • The first thing to know is that a variable of type interface{} contains two Pointers, one to the value type and the other to the actual value
      • *TestStruct * interface{} *TestStruct * interface{}
      • Then, we can reflect the type and value of the input parameter from NilOrNot, which means that the converted value retains the original data type and value
      • Finally, in the following example, the value of the parameter passed in is still null, but it points to a different type, so it’s not nil
package main

import "fmt"

type TestStruct struct{}

func NilOrNot(v interface{}) bool {
	fmt.Println(fmt.Sprintf("%v,%T",v,v)) // <nil>,*main.TestStruct
	return v == nil
}

func main(a) {
	var s *TestStruct
	fmt.Println(s == nil) // true
	fmt.Println(fmt.Sprintf("%v,%T",s,s))// <nil>,*main.TestStruct
	fmt.Println(NilOrNot(s)) // #=> false
}
Copy the code

2. Interface low-level implementation

2.1 What are the basic components of interface?

  • Interface classification: There are two kindsifaceeface
  • Runtime /runtime2.go
  • Note: for the following analysis, I will directly annotate the general meaning of each field in Chinese in the code. At present, I have not actually touched this field (may be used later in the elaboration and in-depth writing reflection?). So I won’t go into details, but if you want to know more about it, you can search for others on the Internet

2.3 iface

  • ** What is iFace? ** Contains the interface to the method
type iface struct {
	tab  *itab // A pointer to the itab type
	data unsafe.Pointer // describes specific values
}

type itab struct {
	inter *interfacetype // Interface type
	_type *_type // Generic type information
	hash  uint32 // is a copy of _type. Hash for quick determination of the target type
	_     [4]byte
    // Store the interface method corresponding to the specific data type of the method address, implement the specific data type
	fun   [1]uintptr // variable sized. fun[0]==0 means _type does not implement inter.
}
Copy the code
  • Runtime. _type, the code is as follows
// _type is actually a structure that describes the various data types in the Go language
// Many other types are managed based on this structure
type _type struct {
	size       uintptr // The size of the memory occupied by the type
	ptrdata    uintptr // size of memory prefix holding all pointers
	hash       uint32 // Is used to quickly determine whether types are equal
    // Type of flag, related to reflection
	tflag      tflag
    // Memory alignment is related
	align      uint8
	fieldAlign uint8
    // Type number
	kind       uint8
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	equal func(unsafe.Pointer, unsafe.Pointer) bool
	// gcdata stores the GC type data for the garbage collector.
	// If the KindGCProg bit is set in kind, gcdata is a GC program.
	// Otherwise it is a ptrmask bitmap. See mbitmap.go for details.
	gcdata    *byte
	str       nameOff
	ptrToThis typeOff
}

// Examples of _type based types, arrays, and functions
type arraytype struct {
	typ   _type
	elem  *_type
	slice *_type
	len   uintptr
}
type functype struct {
	typ      _type
	inCount  uint16
	outCount uint16
}
Copy the code

2.2 eface

  • What is eface: No interface with methods
  • The implementation code is as follows:
type eface struct {
	_type *_type / / same as above
	data  unsafe.Pointer / / same as above
}
Copy the code

3. Reference links

  • www.reddit.com/r/golang/co…
  • Golang. Design/go – question…
  • Legendtkl.com/2017/07/01/…
  • Golang. Design/go – question…