Go basics summary

Go basics summary

Variable declaration

Variables in Go language can only be used after declaration (variables need to be defined in advance) and must be used after declaration (if not applicable, an error will be reported)

Standard statement

var Variable name variable type

example:

var name string
var id int
var isOk bool

Multivariable declarations can be integrated together

var (
	name string
	id int
	isOk bool

)

Variable initialization

When the Go language declares a variable, it will automatically initialize the memory area corresponding to the variable.

var Variable name variable type = expression

example:

var name string = "A2rcher"
var id int = 123

Type inference

The Go language provides a simple way to automatically infer the variable type after the subsequent initialization operation without providing the variable type

var name = "A2rcher"
var id = 123

Short variable declaration

In the functions learned later, you can also declare a variable in a simpler way (which is also the most commonly used declaration method). Use: = to declare and initialize the variable

package main
import (
	"fmt"
)
var m = 100 //global variable

func main(){
	n:=100
	m:=300//Declare and initialize local variables
	fmt.Println(m, n)
}

Anonymous variable

The so-called anonymity, in popular terms, means that variables without names are underlined_ Indicates that anonymous variables do not occupy namespaces (variables must be used after declaration in Go language, except anonymous variables), and memory will not be allocated, so there are no duplicate declarations between anonymous variables.

package main

import "fmt"

func foo() (string, int) {

	return "A2rcher", 20
}

func main() {
	x, _ := foo()
	_, y := foo()

	fmt.Println("x=", x, "y=", y)

}

constant

There is also a constant in the variable, which is an eternal value relative to the variable. For the variable, you can directly define the type without assignment at the beginning, but for the constant, it needs to be assigned at the time of definition. Use const

const p = 3.1415
const e = 2.7182

Multiple constant declarations can be integrated together

const (
	p = 3.1415
	e = 2.7182
)

iota constant calculator

iota is a constant calculator in Go language, which is used in constant expressions.

package main

import "fmt"

const (
	n1 = iota
	n2
	n3
	n4
)

func main() {

	fmt.Println(n1)//0
	fmt.Println(n2)//1
	fmt.Println(n3)//2
	fmt.Println(n4)//3
}

Iota will be reset to 0 when const keyword appears. Each new row constant declaration in const will make iota count once (iota can be understood as the row index in const statement block). Using iota simplifies the definition and is useful in defining enumerations.

Use underline_ You can skip one of them

package main

import "fmt"

const (
	n1 = iota//0
	_		 //1
	n2		 //2
	n3		 //3
	n4		 //4
)

func main() {

	fmt.Println(n1)//0
	fmt.Println(n2)//2
	fmt.Println(n3)//3
	fmt.Println(n4)//4
}

data type

integer

typedescribe
uint8Unsigned 8-bit integer (0 to 255)
uint16Unsigned 16 bit integer (0 to 65535)
uint32Unsigned 32-bit integer (0 to 4294967295)
uint64Unsigned 64 bit integer (0 to 18446744073709551615)
int8Signed 8-bit integer (- 128 to 127)
int16Signed 16 bit integer (- 32768 to 32767)
int32Signed 32-bit integer (- 2147483648 to 2147483647)
int64Signed 64 bit integer (- 9223372036854775808 to 9223372036854775807)

Special integer

typedescribe
uintuint32 on a 32-bit operating system and uint64 on a 64 bit operating system
intIt is int32 on 32-bit operating system and int64 on 64 bit operating system
uintptrUnsigned integer used to hold a pointer

float

The Go language supports two floating-point numbers: float32 and float64. These two floating-point data formats comply with IEEE 754 standard: the maximum range of floating-point numbers of float32 is about 3.4e38, which can be defined by constant: math MaxFloat32. The maximum range of floating-point numbers in float64 is about 1.8e308, which can be defined with a constant: math MaxFloat64.

When printing floating-point numbers, you can use fmt package with verb% f, and the code is as follows:

package main
import (
        "fmt"
        "math"
)
func main() {
        fmt.Printf("%f\n", math.Pi)
        fmt.Printf("%.2f\n", math.Pi)
}

complex

complex64 and complex128

var c1 complex64
c1 = 1 + 2i
var c2 complex128
c2 = 2 + 3i
fmt.Println(c1)
fmt.Println(c2)

The complex number has real and imaginary parts. The real and imaginary parts of complex64 are 32 bits, and the real and imaginary parts of complex128 are 64 bits.

Boolean

character string

byte and run

operator

operatordescribe
+Add
-subtract
*Multiply
/be divided by
%Seeking remainder
operatordescribe
==Check whether the two values are equal. If they are equal, return True; otherwise, return False.
!=Check whether the two values are not equal. If not, return True; otherwise, return False.
>Check whether the left value is greater than the right value. If yes, return True; otherwise, return False.
>=Check whether the left value is greater than or equal to the right value. If yes, return True; otherwise, return False.
<Check whether the left value is less than the right value. If yes, return True; otherwise, return False.
<=Check whether the left value is less than or equal to the right value. If yes, return True; otherwise, return False.
operatordescribe
&&Logical AND operator. True if both operands are true, otherwise False.
||Logical OR operator. True if both operands have a true, otherwise False.
!Logical NOT operator. False if the condition is True, otherwise True.
operatordescribe
&The binary phase and corresponding to each of the two numbers involved in the operation. (only when both digits are 1 is 1)
|The binary phase or corresponding to each of the two numbers involved in the operation. (if one of the two is 1, it will be 1)
^The corresponding binaries of the two numbers involved in the operation are different or, when the corresponding binaries are different, the result is 1. (1 if two digits are different)
<<Shifting n bits to the left is multiplied by 2 to the nth power. "A < < b" means that all binary bits of a are shifted to the left by bit b, the high bit is discarded, and the low bit is supplemented by 0.
>>Shifting n bits to the right is divided by 2 to the nth power. "A > > b" shifts all binary bits of a to the right by b bits.
operatordescribe
=A simple assignment operator assigns the value of an expression to an lvalue
+=Add and assign
-=Subtraction before assignment
*=Multiply and assign
/=Divide and assign
%=Assign value after remainder
<<=Left shift assignment
>>=Assignment after shift right
&=Bitwise and post assignment
|=Bitwise or post assignment
^=Assignment after bitwise XOR

Process control

if else

for Initial statement;Conditional expression;End statement{
	Circular statement
}

example:

package main

import "fmt"

func main() {
	for i := 0; i < 10; i++ {
		fmt.Println(i)
	}
}

The initial statement of the for loop can be ignored, but used as a semicolon separated from; Still have to.

package main

import "fmt"

var i = 0

func main() {
	for ; i < 10; i++ {
		fmt.Println(i)
	}
}

The end statement of the for loop can also be omitted

package main

import "fmt"

var i = 0

func main() {
	for i < 10 {
		fmt.Println(i)
		i++
	}
}

For range

Key value loops can be used for traversal, slicing, map, and channel. Follow the rules

  1. Array, slice, string return index and value.
  2. map returns keys and values.
  3. Channel returns only the values within the channel.

switch

Goto (jump to specified label)

The use of goto can be understood as follows. In a loop, when it runs to a certain position, I don't want it to continue running, but jump to other places. At this time, goto can be used to simplify the implementation process of some code.

func gotoDemo1() {
	var breakFlag bool
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// Set exit label
				breakFlag = true
				break
			}
			fmt.Printf("%v-%v\n", i, j)
		}
		// Outer loop judgment
		if breakFlag {
			break
		}
	}
}

Code can be simplified by using goto statement:

func gotoDemo2() {
	for i := 0; i < 10; i++ {
		for j := 0; j < 10; j++ {
			if j == 2 {
				// Set exit label
				goto breakTag
			}
			fmt.Printf("%v-%v\n", i, j)
		}
	}
	return
	// label
breakTag:
	fmt.Println("end for loop")
}

break

Jump out of loop

continue

Continue next cycle

array

array define

var Variable name [Number of elements]T
var a [3]int
var b [4]string

Array initialization

package main

import "fmt"

func main() {

	var testArray [3]int
	var numArray = [3]int{1, 2, 3}
	var strArray = [3]string{"a", "b", "c"}
	fmt.Println(testArray)
	fmt.Println(numArray)
	fmt.Println(strArray)
}

Use [...] to automatically determine the number of elements according to the initial value

package main

import "fmt"

func main() {

	var testArray [3]int
	var numArray = [...]int{1, 2, 3,4,5}
	var strArray = [...]string{"a", "b", "c", "d","f","v"}
	fmt.Println(testArray)
	fmt.Println(numArray)
	fmt.Println(strArray)
}

Array traversal

for loop traversal

package main

import "fmt"

func main() {

	var testArray [3]int
	var numArray = [...]int{1, 2, 3, 4, 5}
	var strArray = [...]string{"a", "b", "c", "d", "f", "v"}
	fmt.Println(testArray)
	fmt.Println(numArray)
	fmt.Println(strArray)
	for i := 0; i < len(numArray); i++ {
		fmt.Println(i)
	}
	for v := 0; v < len(strArray); v++ {
		fmt.Println(strArray[v])

	}
}

for range traversal

package main

import "fmt"

func main() {

	var testArray [3]int
	var numArray = [...]int{1, 2, 3, 4, 5}
	var strArray = [...]string{"a", "b", "c", "d", "f", "v"}
	fmt.Println(testArray)
	fmt.Println(numArray)
	fmt.Println(strArray)
	for i, v := range numArray {
		fmt.Println(i, v)
	}
	fmt.Println("----------------------------------------------------")
	for m, n := range strArray {
		fmt.Println(m, string(n))
	}
}

The operation results clearly show that there are differences between them.

The result of the for loop traversal does not print out the corner mark, but directly.

When the for range loop traverses the results, the corresponding corner marks are also printed, so we can improve it. Using anonymous variables can make the results of for range the same as those of the for loop.

package main

import "fmt"

func main() {

	var testArray [3]int
	var numArray = [...]int{1, 2, 3, 4, 5}
	var strArray = [...]string{"a", "b", "c", "d", "f", "v"}
	fmt.Println(testArray)
	fmt.Println(numArray)
	fmt.Println(strArray)
	for _, v := range numArray {
		fmt.Println(v)
	}
	fmt.Println("----------------------------------------------------")
	for _, n := range strArray {
		fmt.Println(string(n))
	}
}

In the same principle, you can traverse multiple arrays.

section

Slicing is very similar to array, but slicing is equivalent to a layer of encapsulation based on the array type, which can operate a data set faster than array.

Slice definition

var Variable name [Number of elements]T

You can see that as like as two peas, his initialization is the same.

Slice length and capacity

Using the built-in function len(),cap() can calculate the length and capacity of the slice

package main

import "fmt"

func main() {

	var test1Slice [3]int
	fmt.Println(len(test1Slice))
	fmt.Println(cap(test1Slice))
	var test2Slice = [...]string{"a", "b", "c", "d", "e", "f"}
	fmt.Println(len(test2Slice))
	fmt.Println(cap(test2Slice))
}

expression

The slice expression has two definitions: low and high to represent the limit value in the slice

func main() {
	a := [5]int{1, 2, 3, 4, 5}
	s := a[1:3]  // s := a[low:high]
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}
a[2:]  // Equivalent to a[2:len(a)]
a[:3]  // Equivalent to a[0:3]
a[:]   // Equivalent to a[0:len(a)]

The make() function constructs slices

make([]T,Number of elements, slice capacity)

example:

func main(){
	a := make([]int,2,10)
}

reference resources

Determine whether the slice is empty

You must use len(s)==0 to judge, not nil comparison.

Add element with append() method

The append() method adds elements for the same slice. You can add one or more at a time, or add another element in other slices.

package main

import "fmt"

func main() {
	var s []int
	s = append(s, 1)
	s = append(s, 2, 3, 4)
	s2 := []int{2, 3, 4}
	s = append(s, s2...)
	fmt.Println(s)
}

map usage

map: is an unordered key value based data structure that must be initialized before it can be used.

map definition

map[keyType]valueType
  • KeyType: indicates the type of key.
  • ValueType: indicates the type of value corresponding to the key.

map initialization

The default initial value of map is nil. Use the make() function to allocate memory for initialization:

make(map[keyType]valueType,[cap])

cap represents the capacity of the map. Although this parameter is not necessary, we should specify an appropriate capacity for the map when initializing it.

map usage

package main

import "fmt"

func main() {

	sourceMap := make(map[string]int, 20)
	sourceMap["A2rcher"] = 20
	sourceMap["emo"] = 30
	fmt.Println(sourceMap)
	fmt.Printf("type  %T\n", sourceMap)

}

map can be filled with elements at the time of declaration:

package main

import "fmt"

func main() {

	sourceMap := make(map[string]int, 20)
	sourceMap["A2rcher"] = 20
	sourceMap["emo"] = 30
	fmt.Println(sourceMap)
	fmt.Printf("type  %T\n", sourceMap)
	fmt.Println("***************")
	sourceTest := map[string]int{
		"lucher": 20,
		"xs":10,
	}
	fmt.Println(sourceTest)


}

Determine whether the key value pair exists

package main

import "fmt"

func main() {

	sourceMap := make(map[string]int, 20)
	sourceMap["A2rcher"] = 20
	sourceMap["emo"] = 30
	fmt.Println(sourceMap)
	fmt.Printf("type  %T\n", sourceMap)
	fmt.Println("***************")
	sourceTest := map[string]int{
		"lucher": 20,
		"xs":     10,
	}
	fmt.Println(sourceTest)
	fmt.Printf("type %T\n", sourceTest)

	fmt.Println("______________________________")
	v, ok := sourceMap["emo"]
	if !ok {
		fmt.Println("No one was found")
	} else {
		fmt.Println(v)
	}

}

map traversal

for range traversal

package main

import "fmt"

func main() {

	sourceMap := make(map[string]int, 20)
	sourceMap["a"] = 90
	sourceMap["b"] = 100
	sourceMap["c"] = 60

	for k, v := range sourceMap {
		fmt.Println(k, v)
	}
}

If you only want to traverse the previous key, you can omit v. But if you want to traverse value, you need the help of anonymous variables.

package main

import "fmt"

func main() {

	sourceMap := make(map[string]int, 20)
	sourceMap["Zhao"] = 90
	sourceMap["money"] = 100
	sourceMap["Sun"] = 60

	for k, v := range sourceMap {
		fmt.Println(k, v)
	}
	for k := range sourceMap {
		fmt.Println(k)
	}
	for _, m := range sourceMap {
		fmt.Println(m)

	}
}

The delete() function deletes key value pairs

Slice whose element is map type

This can be understood as that in the slice, the type of each element is map.

For example:

var a = make([]map[string]int,3)

map with value of slice type

This can be understood as that in the map function, the key value is a slice.

For example:

var a1 = make(map[string][]int,3)

function

Function The most important part

Function definition

func Function name(parameter)(Return value){
	Function body
}

example:

func TestFunction(x int,y,int)int{
	return x + y
}

For the parameter part, if the two parameter types are the same, it can be simplified

func TestFunction(x,y int)int{
	return x + y
}

Variable parameters

Variable parameter means that the number of parameters is not fixed, and the reference array

Return value

Functions in Go language support multiple return values. If a function has multiple return values, all return values must be wrapped with ().

func calc(x, y int) (int, int) {
	sum := x + y
	sub := x - y
	return sum, sub
}

Return value naming

When defining a function, you can name the return value, use these variables directly in the function body, and finally return it through the return keyword.

For example:

func calc(x, y int) (sum, sub int) {
	sum = x + y
	sub = x - y
	return
}

Return value supplement

When the return value type of one of our functions is slice, nil can be regarded as a valid slice. There is no need to display and return a slice with length of 0.

func someFunc(x string) []int {
	if x == "" {
		return nil // There is no need to return [] int{}
	}
	...
}

global variable

For variables defined outside the function, global variables can be accessed inside the function

local variable

Variables defined within a function can only be accessed within a function.

be careful:

If local variables and global variables become famous, limited access to local variables.

Define function type

type Function type func(int ,int) int

Function as parameter

package main

import "fmt"

func add(x, y int) int {
	return x + y

}

func calc(x, y int, op func(int, int) int) int {
	return op(x, y)
}
func main() {
	ret2 := calc(10, 20, add)
	fmt.Println(ret2)

}

Function as return value

func do(s string) (func(int, int) int, error) {
	switch s {
	case "+":
		return add, nil
	case "-":
		return sub, nil
	default:
		err := errors.New("Unrecognized operator")
		return nil, err
	}
}

Anonymous function

An anonymous function is a function without a name. You can assign a function to a variable or take a function as a return value.

func(parameter)(Return value){
	Function body

}

Anonymous functions cannot be called like ordinary functions. They need to be saved in a variable (that is, assignment) and then executed.

package main

import "fmt"

func test() {
	func () {
		fmt.Println("Anonymous function")
	}()
}
func main() {
	test()
}


Anonymous function execution:

func test() {
	func () {
		fmt.Println("Anonymous function")
	}()//Adding parentheses after is equivalent to execution
}

Or assignment:

package main

import "fmt"

func test() func() {
	return func() {
		fmt.Println("Anonymous function")
	}
}
func main() {
	r := test()
	r()

}

closure

A closure is an entity composed of a function and its associated reference environment. Simply put, closure = function + reference environment.

package main

import "fmt"

//Simple example of closure / / closure concept closure = function + reference of outer variable

func test() func() {
	name := "A2rcher"
	return func() {
		fmt.Println("Anonymous function",name) // If the calling variable cannot be found in the anonymous function, it will look for the outer layer
	}									//This outer variable is not a global variable, but a local variable in the function test()
}
func main() {
	r := test() // r refers to variables in the function test() and anonymous functions. It can be said that r is a closure at this time
	r()

}

Closures can also be written like this (a typical example)

package main

import "fmt"

//Simple example of closure / / closure concept closure = function + reference of outer variable

func test(name string) func() {

	return func() {
		fmt.Println("Anonymous function", name) 
	}
}
func main() {
	r := test("A2rcher") 
	r()

}

example:

Two classic examples [refer to blog]( The basic function of Go language | Li Wenzhou's blog (liwenzhou.com))

panic & recover & defer

panic/recover: it can be understood as an exception handling mode (but there is no exception handling mechanism in Go language, which is just convenient for understanding),

package main

import "fmt"

//panic and recover

func a() {
	fmt.Println("func is a")
}

//recover must be used with defer, and defer must be defined before panic.
func b() {
	defer func() {
		err := recover()
		if err != nil { //If err is not equal to nil, the program is wrong
			fmt.Println("func b is err ")
		}
	}()
	panic("func is b")
}

func c() {
	fmt.Println("func is c")
}

func main() {
	a()
	b()
	c()

}

During program running, panic was thrown in funcB, resulting in program crash and abnormal exit. At this time, we can recover the program through recover and continue to execute it later.

Built in function

Built in functionintroduce
closeIt is mainly used to close the channel
lenIt is used to find the length, such as string, array, slice, map and channel
newIt is used to allocate memory. It is mainly used to allocate value types, such as int and struct. The pointer is returned
makeIt is used to allocate memory. It is mainly used to allocate reference types, such as chan, map and slice
appendUsed to append elements to arrays and slice s
panic and recoverUsed for error handling

Pointer

There is no offset and operation of pointer in Go language. You only need to understand three concepts and remember two symbols: pointer address, pointer type, pointer value, & (take address) and * (take value according to address)..

Post a link, big guy or big guy

structural morphology

Type aliases and custom types

Type defines the keyword type

type myInt int
//Define myInt as int type

Structure definition

type Type name struct{
	Field name field type
	Field name field type
	...
}

Because Go language is not an object-oriented programming language, but an interface oriented programming language, it does not have the relationship of polymorphic inheritance like java. It implements object-oriented programming through struct in Go language. (struct YYDS!)

  • Type name: identifies the name of a user-defined structure. It cannot be repeated in the same package.
  • Field name: indicates the field name of the structure. Field names in structures must be unique.
  • Field type: indicates the specific type of structure field.

A simple example:

type Person struct{
	name string
	address string
	age int
	sex string
}

Customize a Person type. It has four fields: name, address, age and sex, which represent self content respectively. If I want to use a field in Person, I can call Person directly.

Structure instantiation

Memory usage can be allocated only after the structure is instantiated (user-defined types can be used only after instantiation)

Since the structure itself is a common type, the structure can be declared like a variable

var Structure instance structure type

example:

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func main() {

	var p1 Person
    //Pass To access the fields of the structure (member variables), such as p1.name and p1.age.
	p1.name = "A2rcher"
	p1.age = 20

	fmt.Println(p1)
}

Anonymous structure

Anonymous structure is used to process some temporary data. For example, I now use functions A and B, but I need to use c data temporarily. Anonymous structure can be used at this time.

package main

import "fmt"

type Person struct {
	name string
	age  int
}

func main() {

	var p1 Person
	p1.name = "A2rcher"
	p1.age = 20

	var user struct {
		Name string `json:"name"`
		Age  int    `json:"age"`
	}
	user.Age = 30
	user.Name = "emo"

	fmt.Println(p1)
	fmt.Println(user)

}

Pointer type structure

Pointer type structure is used in most cases. You can instantiate the structure through the new keyword to get the address of the structure. (differences between new and make and built-in functions and pointers in scene reference functions)

Method and receiver

package main

import "fmt"

//Person is a structure
type Person struct {
	name string
	age  int
}

//The constructor is a constructor of type Person
func NewPerson(name string, age int) *Person {
	return &Person{
		name: name,
		age:  age,
	}
}

//Definition method
func (p Person) Dream() {
	fmt.Printf("%s My dream is to learn English well Go language\n", p.name)

}
func main() {

	p1 := NewPerson("A2rcher", int(20))
	p1.Dream()
}

Nested structure

A nested structure is literally a nested structure

package main

import "fmt"

//Nested structure

type Address struct {
	Province string
	City     string
}
type Person struct {
	Name    string
	Gender  string
	Age     int
	Address Address //Nest another structure

}

func main() {
	p1 := Person{
		Name:   "A2rcher",
		Gender: "male",
		Age:    20,
		Address: Address{
			Province: "aaa",
			City:     "fas",
		},
	}
	fmt.Printf("%#v \n", p1)
	fmt.Println(p1.Name, p1.Gender, p1.Age, p1.Address)

}

For the nested part of the structure, if the structure is too large, it will be very messy to nested, and it may be confused when it is finally called, so a new concept - the anonymous field of the structure can be introduced.

Anonymous field of structure

Generally speaking, the fields in the structure have no name, like this

type Test struct{
	string
	int
}

Just because the fields of the structure are anonymous (no name), there will be some special cases. For example, both name and gender are string types. If the anonymous fields of the structure are used, there will be duplication and an error will be reported.

Under what circumstances is the anonymous field of the structure used? Back to the nested structure section,

We have defined a type named Address and nested it in Person. If we use the anonymous field of the structure, can we omit the previously defined variable name and directly use the type name, so the code can be changed to this

package main

import "fmt"

//Nested structure

type Address struct {
	Province string
	City     string
}
type Person struct {
	Name    string
	Gender  string
	Age     int
	Address //Nest anonymous fields of another structure

}

func main() {
	p1 := Person{
		Name:   "A2rcher",
		Gender: "male",
		Age:    20,
		Address: Address{
			Province: "aaa",
			City:     "fas",
		},
	}
	fmt.Printf("%#v \n", p1)
	fmt.Println(p1.Province, p1.City)

}

Can still be called.

Nesting of structures can simulate inheritance relationships

//Animal
type Animal struct {
	name string
}

func (a *Animal) move() {
	fmt.Printf("%s Can move!\n", a.name)
}

//Dog dog
type Dog struct {
	Feet    int8
	*Animal //Inheritance through nested anonymous structs
}

func (d *Dog) wang() {
	fmt.Printf("%s Yes, woof, woof~\n", d.name)
}

func main() {
	d1 := &Dog{
		Feet: 4,
		Animal: &Animal{ //Note that nested structure pointers
			name: "Lele",
		},
	}
	d1.wang() //Lele will bark, bark~
	d1.move() //Lele can move!
}

Interface

Important things are to be repeated for 3 times!!!

Structure is a type, an abstract type!

Structure is a type, an abstract type!

Structure is a type, an abstract type!

Why are there interfaces? What is the difference between his interface and other languages?

Go language is an interface oriented definition method:

type Interface type name interface{
	Method name 1 (Parameter list 1) Return value list 1
	......
}

The existence of an interface is equivalent to merging the repeated methods implemented by some functions. It can be understood as defining a rule that only cares about (Methods) and does not care about (data) in methods.

Conditions for implementing the interface

An interface can be understood as a list of methods to be implemented. Generally, the interface name is defined and followed by the method name + er ®

//Define a mover interface
type mover interface{
	move()
}

Interface type variable

The interface type variable can store all instances that implement the interface.

func main() {
	var x mover // Declare a variable x of type mover
	a := cat{}  // Instantiate a cat
	b := dog{}  // Instantiate a dog
	x = a       // You can assign a cat instance directly to x
	x.say()     // cat 
	x = b       // You can assign a dog instance directly to x
	x.say()     // Woof, woof
}

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

What is the difference between using a value receiver to implement an interface and using a pointer receiver to implement an interface? Next, let's look at the difference through an example.

We have a Mover interface and a dog structure.

type Mover interface {
	move()
}

type dog struct {}

Value receiver implementation interface

func (d dog) move() {
	fmt.Println("Dogs can move")
}

At this time, the dog type implements the interface:

func main() {
	var x Mover
	var wangcai = dog{} // Wangcai is a dog type
	x = wangcai         // x can receive dog types
	var fugui = &dog{}  // Wealth is a * dog type
	x = fugui           // x can receive * dog type
	x.move()
}

From the above code, we can find that after using the value receiver to implement the interface, variables of dog structure or structure pointer * dog type can be assigned to the interface variable. Because the Go language has syntax sugar for evaluating pointer type variables, the dog pointer fugui will automatically evaluate * fugui.

Pointer receiver implementation interface

With the same code, let's test the difference between using pointer recipients:

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 cannot receive dog type
	var fugui = &dog{}  // Wealth is a * dog type
	x = fugui           // x can receive * dog type
}

At this time, the Mover interface is implemented with the * dog type, so the wangcai of the dog type cannot be passed to x. at this time, x can only store the value of the * dog type.

Empty interface

An empty interface is an interface that does not define any methods. Therefore, any type implements an empty interface.

Variables of empty interface type can store variables of any type.

func main() {
	// Define an empty interface x
	var x interface{}
	s := "Hello"
	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)
}

Empty interface application:

  1. As an argument to a function
  2. As the value of mao
// Empty interface as function parameter
func show(a interface{}) {
	fmt.Printf("type:%T value:%v\n", a, a)
}
// Empty interface as map value
	var studentInfo = make(map[string]interface{})
	studentInfo["name"] = "A2rcher"
	studentInfo["age"] = 18
	studentInfo["married"] = false
	fmt.Println(studentInfo)

Concurrent

goroutine

Keywords: Go computer language

Added by lhcpr on Thu, 30 Dec 2021 23:45:53 +0200