Chapter 1 Introduction to Go

Try a go

package main
import "fmt"
func main(a)  {
	fmt.Println("hello word")}Copy the code

Chapter 2 Basic Grammar of Go

2.1 variable

2.1.1. Variables in GO are divided into local variables and global variables
  • Local variables are defined inside parentheses {}, which are also the scope of local variables
  • Global variables are variables defined outside the function and parentheses {}
2.1.2. Variable declarations
Format:varVariable name Variable typeCopy the code

Declare uninitialized variables in batches

var {
    a int
    b string
    c []float32
    e struct {
        x int
        y string}}Copy the code

Initialize a variable

var a int = 20# Standard declaration formatvar b = 30# Autoinfer type format C :=40Initialization declaration format, preferredCopy the code
2.1.3. Multiple assignment of variables

Take simple algorithm switching as an example, the traditional way of writing it is as follows

var a int = 10
var b int = 20
b,a = a,b

Copy the code
2.1.4. Anonymous variables

A function in Go can return multiple values, but not all of them are used. Anonymous variables can be replaced by “_”, which takes no namespace and allocates no memory

func GetData(a)(int.int){
    return 10.20
}
a,_ := GetData() // Discard the second return value
_,b = GetData()// Discard the first return value
Copy the code

2.2 Data Types

2.3 Printing and Formatting

2.4 Data type conversion

Go language uses the method of data type conversion with parentheses, such as T(expression). T indicates the type to be converted

a := 10

b := string(a) // Convert int to string
c := float32(a) // Convert int to float
Copy the code

2.5 constant

A constant is a constant value relative to a variable. A constant is a simple identifier that cannot be modified while the program is running

The format is as follows:constIdentifier [type] = valueconst PAI string = "abc"
Copy the code
  • 2.5.1 Constants are used for enumeration
const (
	USERNAME = "geinihua"
	PASSWORD = "geinihua"
	NETWORK = "tcp"
	SERVER = "10.247.22.146"
	PORT = "3306"
	DATABASE = "demo"
)
	dsn := fmt.Sprintf("%s:%s@%s(%s:%d)/%s",USERNAME,PASSWORD,NETWORK,SERVER,PORT,DATABASE)

Copy the code

If no type and initial value are specified in a constant group, the value is the same as the non-empty constant value on the previous line

const (
    a=10
    b
    c
)

fmt.PrintLn(a,b,c) // Output 10 10 10 10
Copy the code
2.5.2 iota enumeration
  • Iota constant automatic generator, every other line, automatically add 1
  • Iota is used to assign values to constants
  • Iota is reset to 0 when it encounters the next const
  • Multiple constants can be written as one IOTA, in brackets
  • Multiple assignments, on the same line, have the same value

3. Process control

  • 3.1 If condition statement
func max(num1, num2 int) int {
   /* Declare local variables */
   var result int

   if num1 > num2 {
   	result = num1
   } else {
   	result = num2
   }
   return result
}

Copy the code
  • 3.2 Switch Conditional selection statement

   grade := ""
   score := 88.5

   switch true {
   case score >=90:
   	grade = "A"
   case score >=80:
   	grade = "B"
   case score >=70:
   	grade = "C"
   default:
   	grade="E"
   }

   fmt.Printf("Your registration is: %s\n",grade )
Copy the code
  • 3.3 For loop statement
The first way:for i:=0; i<=20; i++ { fmt.Printf("%d\n", I)}var i int
	for i<=20  {
		fmt.Printf("%d\n", I)}for.range) : STR: ="123 abcabc good"
	for i,value := range str{
		fmt.Printf("ASCII value for bit %d =%d, character %c\n",i,value,value)
	}
   
Copy the code

4.Go language functions and Pointers

4.1 the function
func(Parameter list)(Returns a list of parameters){
  / / the function body
}
Copy the code
4.1.3 Functional variables

A function variable is a function stored as a value in a variable.

In Golang, a function is also a type and can be stored in a variable just like any other type

type myFunc func(int) bool
func main(a){

   nums:=[]int{10.20.40.16.17.3030.49849.204394.43943.2923.23923,}
   fmt.Println(filter(nums,isEven))
   fmt.Println(filter(nums,isAdd))
}

func filter(arr []int, f myFunc) []int {
   var result []int
   for _, value := range arr {
   	if f(value) {
   		result = append(result, value)
   	}
   }
   return result
}
func isEven(num int) bool{
   if num%2= =0 {
   	return true
   }else {
   	return false}}func  isAdd(num int) bool{
   if num%2= =0 {
   	return false
   }
   return true
}
Copy the code
4.1.4 Anonymous Functions

Anonymous functions do not have function names, only function bodies, and can be assigned as a type to variables.

Anonymous functions are often used to implement callbacks, closures, and so on

1.You can use res1 := directly when defining anonymous functionsfunc (n1 int, n2 int) int {
        return n1 + n2
    }(10.30)  // 10,30 in parentheses is the argument list, corresponding to n1 and n2
    
    fmt.Println("res1=",res1)
    
2.Assign the anonymous function to a variable res1 :=func (n1 int, n2 int) int {
		return n1 + n2
	}
	res2 := res1(50.50)
	fmt.Println("res1=",res2)
    
3.Anonymous functions as callback functionsfunc vist(list []float64,f func(float64))  {
	for _,value:=range list{
		f(value)
	}
}
	List := []float64{1.2.5.20.90}
	vist(List, func(v float64) {
		sqrt := math.Pow(v,2)
		fmt.Println(sqrt)
	})
    
Copy the code
4.1.5 closure
// f returns a function that is a closure. This function does not define variable I itself, but refers to variable I in its environment (function f).
    func f(i int) func(a) int  {
        return func(a) int{
            i++
            return i
        }
    }
	a:=f(0)
	fmt.Println(a()) / / 0
	fmt.Println(a()) / / 1
	fmt.Println(a()) / / 2
	fmt.Println(a()) / / 3

Copy the code
4.1.6 Variable Parameters
Syntax format:funcThe function name(Parameter name... Type)(List of return values){}
Copy the code

This syntax defines a function that takes any number of arguments of any type. The special syntax here is three dots “…” , followed by three dots to indicate that a variable is accepted from there

func Tsum(nums ...int) {
	fmt.Println(nums)
	total:=0
	for _,val := range nums{
		total+=val
	}
	fmt.Println( total)
}
Copy the code
4.1.7 Golang unit test

To start a unit test, prepare a go source file that must end with _test when naming it

Unit Test source files can consist of multiple Test cases, and each Test case function needs to be prefixed with Test, for example:Copy the code
The format is as follows:func TestXXX( t *testing.T )
Copy the code
func sum2(n1 int, args ...int) int {
	sum := n1
	for i := 0; i < len(args); i++ {
		sum += args[i]
	}
	return sum
}
func TestAvaiableSum(t *testing.T) {
	res := sum2(1.23.34.56)
	fmt.Println("res=", res)
}
Copy the code

4.2 a pointer

Pointer a variable that stores the memory address of another variable. Variables are a convenient placeholder. A pointer variable can point to the memory address of any value. In Go, the address character & is used to get the address of the variable. Using & before a variable returns the memory address of the variable

total:=20
fmt.Println("Total memory address",&total)
Copy the code
4.2.1 Declaring Pointers

*T is the type of the pointer variable that points to a value of type T. The * sign is used to specify that the variable is a pointer

var ip *int // A pointer to an integer
var fp *float32 // a pointer to a floating point
Copy the code

Pointer usage flow

1. Define a pointer variable 2. Assign a value to a pointer variable 3. Obtain the value of the pointer variable by accessing the address of the pointer variable. Such as a

type Student struct {
	name string
	age int
	sex int8
}

func TestZhiz(t *testing.T)  {
	s1:=Student{"steven".32.2}
	s2:=Student{"Sunny".10.1}
	var a *Student=&s1 //&s1 memory address
	var b *Student=&s2 //&s2 memory address
	fmt.Printf("S1 of type %T and value %v\n",s1,s1)
	fmt.Printf("S2 is of type %T and value %v\n",s2,s2)
	fmt.Printf("A of type %T and value %v\n",a,a)
	fmt.Printf("B of type %T and value %v\n",b,b)

	fmt.Printf("The value of s1 is equal to the pointer a \n")
	fmt.Printf("The value of s2 is equal to b pointer \n")
	fmt.Printf("*a type %T and value %v\n",*a,*a)
	fmt.Printf("*b type %T and value %v\n",*b,*b)

}
Copy the code
  • Null pointer
if(ptr ! =nil) // PTR is not null
if(ptr == nil)// PTR is null
Copy the code
4.2.2 Using Pointers

1. Modify variable values using Pointers

// The pointer modifies the value of a variable
	a2:=32
	b2:=&a2
	fmt.Println("The value of the a2",a2) / / the value of the a2 32
	fmt.Println("B2 address",b2) / / b2 address 0 xc4200142d8
	fmt.Println("The value of the b2",*b2) / / the value of 32 b2
	*b2++
	fmt.Println("The value of the b2",*b2) / / b2 values of 33
    
Copy the code

2. Use Pointers as arguments to the function

Using a pointer to a primitive data type as an argument to a function makes it possible to modify the data passed in because a pointer as an argument to a function simply assigns a pointer to the memory it points to

func main(a){
orgi:=68
		ptr:=&orgi
		change(ptr)
		fmt.Println("The value of orgi after the function is executed.",orgi) // Orgi is 20 after the function is executed
}
func change(p *int)  {
	*p=20
}

Copy the code
4.2.3 Pointer arrays
// Array of Pointers
// Format: var PTR [3]*string

ptrArr:=[COUNT]string{"abc"."ABC"."123"."8888"}

i:=0
// Define pointer arrays
var ptrPoint [COUNT]*string
fmt.Printf("%T,%v \n",ptrPoint,ptrPoint) //[4]*string,[<nil> <nil> <nil> <nil>]

// Assign the address of each element in the array to the pointer array
	for i=0; i<COUNT; i++ { ptrPoint[i] = &ptrArr[i] } fmt.Printf("%T,%v \n",ptrPoint,ptrPoint) //[4]*string,[0xc42000e800 0xc42000e810 0xc42000e820 0xc42000e830]

	// Loop over the values in the pointer array
	for i=0; i<COUNT; i++ { fmt.Printf("a[%d]=%v \n",i, *ptrPoint[i])
		//a[0]=abc 
		//a[1]=ABC 
		//a[2]=123 
		//a[3]=8888 
	}
Copy the code

4.2.4 Pointers of Pointers

Pointer variables to Pointers are declared in the following format:

var ptr **int// Use two asterisks
Copy the code

// A pointer to a pointer
var a2 int
var ptr2 *int
var pptr **int
a2=1234
ptr2=&a2
fmt.Println("PTR address",ptr2)
pptr=&ptr
fmt.Println("PPTR address",pptr)

fmt.Printf("Variable a2 = % d \ n",a2)
fmt.Printf("Ptr2 =%d\n",*ptr2)
fmt.Printf("Pointer size PPTR =%d\n",**pptr)
// Output the result
/* PTR address 0xC4200d4140 PPTR address 0xC4200ec000 Variable A2 =1234 Pointer variable ptr2=1234 Pointer quantity PPTR =20 */
Copy the code

4.3 Parameter transfer of functions

4.3.1 Value Passing (Value Passing)
Value passing means that when a function is called, a copy of the actual parameters is passed to the function without affecting the original content dataCopy the code
4.3.2 Passing References (Passing References)
1. Reference passing refers to passing the address of the actual parameter to the function when calling the function, so the modification of the parameter in the function will affect the original content data. 2. The function argument uses a pointer argument. When passing a parameter, it copies a copy of the pointer argument, i.e. the variable address 3. If the parameter of the function is a pointer, when the function is called, although the parameter is passed according to the copy, only a pointer is copied, that is, a memory address, which will not cause memory waste and timeCopy the code

The function passes a value of type int to compare with a reference

package main

import "fmt"

func main(a)  {

	// The function passes a value of type int to compare with a reference
	a:=200
	fmt.Printf("Memory address of variable A %p, value: %v\n",&a,a)
	changeIntVal(a)
	fmt.Printf("Memory address %p of variable A after changeIntVal, value: %v\n",&a,a)
	changeIntPtr(&a)
	fmt.Printf("Memory address %p of variable A after changeIntPtr, value: %v\n",&a,a)
	/* Memory address of variable A 0xC420080008, value: 200 changeIntVal: memory address of parameter N 0xC420080018, value: 200 changeIntVal: memory address of variable A 0xC420080008, value: 200 200 changeIntPtr: memory address of parameter N: 0xC42008A020, value: 0xC420080008 changeIntPtr: memory address of variable A: 0xC420080008, value: 50 */
}
func changeIntVal(n int)  {
	fmt.Printf("ChangeIntVal: memory address of n: %p, value: %v\n",&n,n)
	n=90
}
func changeIntPtr(n *int)  {
	fmt.Printf("ChangeIntPtr: memory address of n: %p, value: %v\n",&n,n)
	*n=50
}
Copy the code

The slice function passes a value to compare with a reference

import "fmt"
func main(a)  {
   // The slice function passes a value to compare with a reference
   a:=[]int{1.2.3.4}
   fmt.Printf("Memory address of variable A %p, value: %v\n",&a,a)
   changeSliceVal(a)
   fmt.Printf("Memory address %p of variable A after changeSliceVal, value: %v\n",&a,a)
   changeSlicePtr(&a)
   fmt.Printf("Memory address %p of variable A after changeSlicePtr, value: %v\n",&a,a)
}
func changeSliceVal(n []int)  {
   fmt.Printf("ChangeSliceVal: memory address of parameter n: %p, value: %v\n",&n,n)
   n[0] =90
}
func changeSlicePtr(n *[]int)  {
   fmt.Printf("ChangeSlicePtr: memory address of n: %p, value: %v\n",&n,n)
   (*n)[1] =50
}
Copy the code

Function pass structure

package main
import "fmt"
type  Teater struct {
   name string
   age int
}
func main(a)  {
   // Function pass struct
   a:=Teater{"xll".200}
   fmt.Printf("Memory address of variable A %p, value: %v\n",&a,a)
   changeStructVal(a)
   fmt.Printf("ChangeStructVal memory address %p, value: %v\n",&a,a)
   changeStructPtr(&a)
   fmt.Printf("Memory address %p of variable A after changeStructPtr, value: %v\n",&a,a)
}
func changeStructVal(n Teater)  {
   fmt.Printf("ChangeStructVal: memory address of n: %p, value: %v\n",&n,n)
   n.name="testtest"
}
func changeStructPtr(n *Teater)  {
   fmt.Printf("ChangeStructPtr: memory address of n: %p, value: %v \n",&n,n)
   (*n).name="ptrptr"
   (*n).age=899
}
Copy the code

Chapter 5. Built-in containers for the Go language

5.1 an array

  • Array syntax
The format is as follows:varVariable name [array length] Data typeCopy the code

1. Array length must be an integer greater than 0, and uninitialized arrays are not nil, that is, there are no empty arrays (unlike slicing) 2. Initialize the array as follows:

var arr = [6]int{1.2.3.4.5.6}
Copy the code

Initialize the number of elements in {} cannot be greater than the number in []. If you ignore the number in [] and do not set the array length, Go sets the array length by default. You can ignore the length of the array in the declaration and replace it with “…” . The compiler automatically calculates the length in the following format

var arr = [...]int{1.2.3.4.5.6}
Copy the code

3. Modify the array content to the available format

arr[2[=100
Copy the code

Array elements can be read by index position, so start at 0. Len () gets the array length

var arr = [...]int{1.2.3.4.5.6}
fmt.Printf(Array length %d \n.len(arr))
Copy the code
  • Array traversal
arr:=[...]int{1.2.3.4.5.6}
// First traversal
for i:=0; i<len(arr); i++ { fmt.Printf(Element value %v\n,arr[i])
}
fmt.Println("-- -- -- -- -- -")
// The second traversal mode
for index,value:=range arr{
	fmt.Printf("%d element value %v\n",index,value)
	}
Copy the code
  • Multidimensional array

A two-dimensional number declaration format is as follows:

varArrName [x][Y] Data typeCopy the code

A two-dimensional array can use loop nesting to retrieve elements


func main(a)  {
	arr:=[5] [2]int{{0.0},
		{1.2},
		{2.4},
		{3.6},
		{4.8}},for i1,v:=range arr{
		for i2,v2:=range v {
			fmt.Printf("arr[%d][%d]=%d\n",i1,i2,v2)
		}
	}

}
Copy the code
  • Arrays are value types

Arrays in Go are not reference types, but value types. When assigned to a new variable, a copy of the original array is made to the new variable, so changes to the new variable do not affect the original array

Section 5.2

  • Slicing concept 1.Go provides a built-in type “slicing” to compensate for the immutable array length. 2. Slicing is a variable-length sequence in which each element is of the same type. 3. Slicing can append elements, which increases the capacity. Compared with array, slicing does not need to set length 4. Slice data structure can be understood as a structure containing three elements. Pointer to the length of the starting position specified by the slice in the array, that is, the length from the beginning position of the slice to the end position of the array

  • Slice the grammar

1. Declare slices

var identifier []typeThe length of the slice does not need to be specified. The default length isnil, the length of0
Copy the code

Use the make() function to create a slice in the following format:

var sliceVar []type = make([]type.len.capSliceVar :=make([]type.len.cap)/ / cap capacity

sliceVar:=make([]int.3.5)
fmt.Printf("len=%d cap=%d slice=%v\n".len(sliceVar),cap(sliceVar),sliceVar) //len=3 cap=5 slice=[0 0 0]
Copy the code

2. Initialize slices. (1) Initialize slices directly

sl:=[]int{1.2.3.4}
Copy the code

(2) Initialize slices by array interception

arr:=[...]int{1.2.3.4.5}
s1:=arr[:]
Copy the code

The slice contains all the elements in the array

s:=arr[startIndex:endIndex] 
Copy the code

Create a new slice of arR from the subscript startIndex to endindex-1, with the length endindex-startIndex up to the last element in arR

s:=arr[startIndex:endIndex]
Copy the code

By default, startIndex starts at the first element of the ARR

s:=arr[startIndex:endIndex]
Copy the code
func main(a)  {
	arr:=[]int{0.1.2.3.4.5.6.7.8}
	printSlice(arr[:6]) //0, 1, 2, 3, 4, 5 does not contain 6 elements
	printSlice(arr[3:)//3 4 5 6 7 8 starts at index 3 and ends
	printSlice(arr[2:5]) //2 3 4 Starts at index 2 (included) and ends at index 5(not included)
}
func printSlice(n []int)  {
	fmt.Printf("len=%d cap=%d slice=%v\n".len(n),cap(n),n)
}
Copy the code

(3) To further understand the capacity of the slice, we can regard the capacity as the total length minus the value of the element passed by the left pointer, for example

s[:0] ——> cap = 6 - 0 =6; s[2:] -- >cap = 6 - 2 = 4.Copy the code
  • Append () and copy()

If the length of the underlying array is 4 and becomes 5 after adding an element, the capacity becomes 42=8; if len=12, cap=12; if an element is added, cap=27=14.

  • A slice does not have any data of its own. It is only a reference to the underlying array. Any modification to the slice will affect the data of the underlying array
  • Slice source code learning

Refer to the blog www.cnblogs.com/xull0651/p/…

func growslice(et *_type, old slice, cap int) slice {
	
	newcap := old.cap
	doublecap := newcap + newcap
	if cap > doublecap {
		newcap = cap
	} else {
		if old.len < 1024 {
			newcap = doublecap
		} else {
			// Check 0 < newcap to detect overflow
			// and prevent an infinite loop.
			for 0 < newcap && newcap < cap {
				newcap += newcap / 4
			}
			// Set newcap to the requested cap when
			// the newcap calculation overflowed.
			if newcap <= 0 {
				newcap = cap}}}return slice{p, old.len, newCap}} from the source code above, in sliceappendThe operation may cause automatic expansion of Slice. The expansion rule is as follows: a. If the capacity of the slice is smaller than that of the slice1024, the capacity during capacity expansion is multiplied by2; Once the capacity size exceeds1024, then the growth factor becomes1.25That is, increase the original capacity by a quarter each time. B. If the capacity of the original array is not reached after expansion, the pointer in the slice still points to the original array. If the capacity of the original array is exceeded after expansion, a new memory will be created and the original values will be copied, which will not affect the original array at all.Copy the code

5.3 the map

  • 5.3.1 concept map

A Map is an unordered collection of key-value pairs. One of the most important aspects of a Map is its ability to quickly retrieve data through keys, which are similar to indexes that point to the value of the data. A Map is a collection, so we can iterate over it in the same way we iterate over arrays and slices. A Map is a reference to a hash table. The type of the Map is Map [key]value, where key and value correspond to one data type, for example: Map [string] String requires that all keys have the same data type and all values have the same data type.

  • 5.3.2 map grammar

Statement of the map

The first method is mapVar :=map[Key]value The second method mapVar :=make(map[key]value type)Copy the code

Map initialization and traversal

	mapVar:=map[string]string{
		"a":"t1"."b":"t2"."c":"t3",}/ / traverse map
	for key, value := range mapVar {
		fmt.Printf("key=%v value=%v\n",key,value)
	}

	// Check if the element exists in the collection
	if value,ok:=mapVar["aa"]; ok { fmt.Println("Existing value",value)
	}else {
		fmt.Println("There is no value")}Copy the code
  • 5.3.3 Map is a reference type

Chapter 6 Go common built-in packages

Please refer to the official website

  • String traversal
str:="Strings package: Iterating over strings with Chinese characters"
   for _, value := range []rune(str) {
   	fmt.Printf("%c\n",value)
   }
Copy the code
  • Json serialization and deserialization

The map serialization

// The first map declaration
	M2:= map[int]string{
		2:"aa".3:"bb",}// The second map declaration
	M:=make(map[int]string)
	M[1] ="aaa"
	M[2] ="bbb"
	res2,error:=json.Marshal(M2)
	res,error:=json.Marshal(M)
	iferror! =nil {
		fmt.Printf("Parsing error")
	}
	fmt.Printf(string(res2))
	fmt.Printf(string(res))
	// Return the result
	//{"2":"aa","3":"bb"}{"1":"aaa","2":"bbb"}
Copy the code

Structure serialization

package main

import (
	"encoding/json"
	"fmt"
)
type Stu struct {
	Name  string `json:"name"`
	Age   int
	HIgh  bool
	sex   string
	Class *Class `json:"class"`
}
type Class struct {
	Name  string
	Grade int
}
func main(a) {
	// Instantiate a data structure to generate a JSON string
	cla := new(Class)
	cla.Name = "Class 1"
	cla.Grade = 3
	stu := Stu{
		"Zhang".18.true."Male",
		cla,// Pointer variable
	}
	//Marshal failed when err! =nil
	jsonStu, err := json.Marshal(stu)
	iferr ! =nil {
		fmt.Println("Error generating JSON string")}//jsonStu is of []byte type, converted to string for easy viewing
	fmt.Println(string(jsonStu)) as you can see from the result, any exportable member (variable starts with a capital letter) can be converted to JSON. The member variable sex cannot be converted to JSON because it is not exportable. If the variable is tagged with JSON, such as json next to Name:"name", then the converted JSON key uses the label "name", otherwise the variable name is used as the key, such as "Age", "HIgh".boolA type is also a value that can be converted directly to JSON. The Channel,complexAnd functions cannot be encoded with JSON strings. Of course, the circular data structure didn't work either, causing Marshal to fall into an infinite loop. Pointer variables that are automatically converted to the value they point to when encoded, such as CLA variables. (Of course, no pointer is passed, StustructClass is a member of ClassstructType, the effect is exactly the same. But Pointers are faster and save memory.// Unmarshal()
	var per_data Stu
	err2 := json.Unmarshal([]byte(jsonStu),&per_data)
	iferr2 ! =nil {
		fmt.Printf("Deserialization error: %v\n", err)
	}
	fmt.Printf("Personal_json deserialization =%v\n", per_data)
	fmt.Printf("per_data=%v\n", *per_data.Class)
    
}
Copy the code

Chapter 7 Go is object-oriented

The structure of the body

  • Anonymous struct and struct anonymous field

Anonymous structures are structures that have no name and can be used directly without the type keyword definition. When you create an anonymous structure, you also create a structure object

	// Anonymous structure
	addr:=struct{
		name string
		age int} {"slaiven".39}
	fmt.Println(addr)
Copy the code

An anonymous field is a field in a structure that has no name and contains only a type that has no field name. If the field has no name, the default type is the field name, and only one anonymous field of the same type can exist

// Anonymous field
	user:=new(User)
	user.string="apce"
	user.int=84
	fmt.Printf(Name %v, age %v,user.string,user.int) // Name apce, age 84
Copy the code
  • Structure nesting

Structure nesting, which treats one structure as a field (property) of another structure, simulates the following two relationships. Aggregation relationships: one class as an attribute of another class must adopt a named structure as field inheritance relationships: one class as a subclass of another class. The relationship between a subclass and its parent. It takes the form of an anonymous field that is the parent of the structure

// Aggregate relationship: one class acts as an attribute of another class
type Address struct {
	province,city string
}
type Person struct {
	name string
	age int
	address  *Address
}

func TestMoudelStrings(t *testing.T)  {
	// Instantiate the Address structure
	addr:=Address{}
	addr.province="Beijing"
	addr.city="Fengtai District"
	// Instantiate the Person structure
	p:=Person{}
	p.name="Strven"
	p.age=28
	p.address=&addr
	fmt.Println("Name:",p.name,"Age:",p.age,"Save.",p.address.province,"City.",p.address.city)
	// If you modify the address data of the Person object, what happens to the address object? For sure
	p.address.city="Daxing District"
	fmt.Println("Name:",p.name,"Age:",p.age,"Save.",p.address.province,"City.",addr.city)
	// Does modifying the Address object affect the Persion object data? For sure
	addr.city="Chaoyang District"
	fmt.Println("Name:",p.name,"Age:",p.age,"Save.",p.address.province,"City.",addr.city)
}
// Inheritance: a class is a subclass of another class. The relationship between a subclass and its parent

type Address struct {
	province,city string
}
type Person struct {
	name string
	age int
	Address Address is the parent of Person
}
func TestMoudelStrings(t *testing.T)  {
	// Instantiate the Address structure
	addr:=Address{}
	addr.province="Beijing"
	addr.city="Fengtai District"
	// Instantiate the Person structure
	p:=Person{"strven".38,addr}
	fmt.Printf("Name :%v Age :% V Province :% V City :%v\n",p.name,p.age,p.Address.province,p.Address.city) // Name: Strven Age :38 Province: Beijing: Fengtai District
}
Copy the code

methods

  • In Go, there are both functions and methods. The essence of a method is a function, but it is different from a function

1. Different meanings. A function is a piece of code with independent functions that can be called many times, while a method is a behavioral function of a class that can only be called by objects of that class. Methods have receivers and functions do not. Go’s methods are functions that scope a variable of a specific type, called receiver. The concept of receiver is similar to the this or self keyword in traditional object-oriented language 3. Methods can have the same name (recipient is different), but functions cannot,

type Per struct {
	name string
	age int
}
func ( p Per ) getData(a)  {
	fmt.Printf("Name: %v Age: %v",p.name,p.age) // Name: AAA Age: 39
}
func TestMethod(t *testing.T)  {
	p1:=Per{"aaa".39}
	p1.getData()
}
Copy the code
  • methods

Methods are inheritable, and if an anonymous field implements a method, the struct containing that anonymous field can also call the method in that anonymous field

type Human struct {
	name, phone string
	age int
}

type Stu struct {
	Human
	school string
}
type Employee struct {
	Human
	company string
}
func TestMethod(t *testing.T)  {
	s1:=Stu{Human{"dav"."1850103930".7},"Luoyang No.1 Middle School"}
	s1.SayHi()
}
func (h *Human) SayHi(a)  {
	fmt.Printf("I'm % S,% D, phone %s\n",h.name,h.age,h.phone)
}
Copy the code
  • Methods to rewrite
type Human struct {
	name, phone string
	age int
}

type Stu struct {
	Human
	school string
}
type Employee struct {
	Human
	company string
}
func TestMethod(t *testing.T)  {
	s1:=Stu{Human{"dav"."1850103930".7}, "Luoyang No.1 Middle School"}
	s2:=Employee{Human{"dav"."1850 * * * * *".17},"Space Shuttle"}
	s1.SayHi()
	
	s2.SayHi()
}
func (h *Human) SayHi(a)  {
	fmt.Printf("I'm % S,% D, phone %s\n",h.name,h.age,h.phone)
}
func (h *Stu) SayHi(a)  {
	fmt.Printf("I'm % S,%d, phone %s, school %s\n",h.name,h.age,h.phone,h.school)
}
func (h *Employee) SayHi(a)  {
	fmt.Printf("I'm % S,% D, phone %s, job %s\n",h.name,h.age,h.phone,h.company)
}
Copy the code

interface

  • Interface definition and implementation

Interfaces in Go are similar to interfaces in Java, which define the behavior of objects. Interfaces specify what an object should do, and it’s up to the object to implement this behavior (implementation details)

type implUser interface {
	run()
	call()
}
type Ameriacan struct{}func (a Ameriacan) run(a)  {
	fmt.Printf("The Americans have run away \n")}func (a Ameriacan) call(a)  {
	fmt.Printf("The American Call () Method" +
		"\n")}func TestOver(t *testing.T)  {

	var user implUser
	user=new(Ameriacan)
	user.run()
	user.call()
}
Copy the code
  • Interface object transformation (type assertion)

Similar to transitions up and down in Java

// Interface object transformation (type assertion)
type Compute interface {
	perimeter() float64 // Implement two types
}
type Rectangle struct {
	a,b float64
}
type Triangle struct {
	a,b,c float64
}

// Define two types of methods,
func (r Rectangle)perimeter(a)  float64 {

	return r.a*r.b
}
func (r Triangle)perimeter(a)  float64 {

	return r.a*r.b*r.c
}

// Interface assertion
func getType(c Compute)  {
	ifinstance,ok:=c.(Rectangle); ok{ fmt.Printf("Rectangle length :%0.2f,%0.2f\n",instance.a,instance.b)

	} else ifinstance,ok:=c.(Triangle); ok { fmt.Printf("Triangle length :%0.2f,%0.2f,%0.2f\n",instance.a,instance.b,instance.c)
	}
}
// Define the return result,
func getResult(s Compute)  {

	fmt.Printf("The result is %.2f \n",s.perimeter())
}
func main(a)  {

	var c Compute
	c = Rectangle{2.0.3.0}
	getType(c)
	getResult(c)
}

Copy the code

Chapter 8 Exception Handling

defer

The defer statement can only occur in a function or method. If there are multiple defer statements, they will be executed in reverse order at the end of the function, and the function will return

func main(a){
	defer funcA()
	funcB()
	defer funcC()
	fmt.Println("Main")
	FuncB executes main executes funcC executes funcA executes */
}
func funcA(a)  {
	fmt.Println("FuncA execution")}func funcB(a)  {
	fmt.Println("FuncB execution")}func funcC(a)  {
	fmt.Println("FuncC execution")}Copy the code

Defer is used in the method

type deferPerson struct {
	name string
	age int
}
func main(a){
	P:=deferPerson{"t0".38}
	defer P.getName()
	fmt.Println("Welcome") 
    /* Welcome name:t0 */
}
func (d deferPerson) getName(a) {
	fmt.Printf("name:%v\n",d.name)
}
Copy the code

Stack latency. When a function has multiple delays called, they are added to a stack and executed in “last in, first out” order


func main(a)  {
	str:="Welcome to One Pice."
	fmt.Printf("Original string :\n %s\n",str)
	fmt.Println("Flipped string:")
	ReverseString(str)
    /* Original string: One Pice welcome everyone to flip the back string: eciP enO */
}

func ReverseString(str string)  {
	for _, value := range [] rune(str) {
		defer fmt.Printf("%c",value)
	}
}
Copy the code

Panic and Recover mechanisms

  • Panic causes the current program to panic, terminates the execution of the program, and interrupts the original process control
  • Recover () allows the program to recover, which intercepts panic errors and must be executed in the defer function for this to work. In normal program execution, calling Revover returns nil
func main(a)  {
	catch(2.8)}func catch(nums ...int)int  {
	defer func(a) {
		if r := recover(a); r! =nil{
			log.Println("[E]",r)
		}
	}()
	return nums[1] * nums[2] * nums[3]}Copy the code

Chapter 9 Go File I/O Operations

9.1 File Information

  • The FileInfo interface
func main(a)  {
	file:="./layout.html"
	printMessat(file)
}
func printMessat(filePath string)  {
	fileinfo,error:=os.Stat(filePath)
	iferror ! =nil {
		fmt.Println("File opening error",error.Error())
	}
	fmt.Printf("File name: %s\n",fileinfo.Name())
	fmt.Printf("File permission: %s\n",fileinfo.Mode())
	fmt.Printf("Directory: %s\n",fileinfo.IsDir())
	fmt.Printf("File last modification permission: %s\n",fileinfo.ModTime())
	fmt.Printf("File size: %s\n",fileinfo.Size())
}
Copy the code
  • The file path
	file1:="/Users/u51/Documents/go_learn/first.go"
	file2:="./layout.html"
	fmt.Printf("Is it an absolute path %v\n",filepath.IsAbs(file1))
	fmt.Printf("Is it an absolute path %v\n",filepath.IsAbs(file2))
	fmt.Printf("Get file absolute path %v\n",filepath.Abs(file2))
	fmt.Printf("Get file absolute path %v\n",filepath.Abs(file2))
Copy the code

9.2 Common File Operations

  • MKdir() Creates a level-1 directory. Os.mkdirall () creates a multi-level directory
  • Create a file

Os.create () creates the file

  • Delete the file

Remove() removes files or empty directories os.removeall () removes all paths and their children,

file,error:=os.Create("test1.csv")
iferror! =nil{
	fmt.Printf("File creation failed")
}
file.Write([]byte("aaa\n"))
file.WriteString("bbbb")
file.WriteString("File")

Copy the code
  • Open and close files

Os.open reads data from the file. The return value n is the number of bytes actually read. If it reads to the end of the file, n is 0 or err is IO

file,error:=os.Open("./test1.csv")
iferror! =nil{
	fmt.Printf("Opening error")}else {
	bs:=make([]byte.1024.1024)
	for{
		n,err:=file.Read(bs)
		if n==0||err==io.EOF{
			fmt.Printf("End of reading file -----")
			break
		}
		fmt.Println(string(bs[:]))
	}
}
defer file.Close()

Copy the code
  • Copy the file
func main(a) {
	srcFile:="./test.csv"
	destFile:="./test1.csv"
	total,err:=copyFiles(srcFile,destFile)
	iferr! =nil{
		fmt.Printf(err.Error())
	}else {
		fmt.Println(Copying "ok",total)
	}
}
func copyFiles(srcfile,destfile string)(int64,error)  {
	file1,err:=os.Open(srcfile)
	iferr! =nil{
		return 0, err
	}
	file2,err:=os.OpenFile(destfile,os.O_RDWR|os.O_CREATE,os.ModePerm)
	iferr ! =nil{
		return 0, err
	}
	defer file1.Close()
	defer file2.Close()
	return  io.Copy(file2,file1)
}
Copy the code

9.3 ioutil package

  • Ioutil package core functions
methods role
ReadFile() Reads all data in the file and returns the byte array read
WriteFile() Writes data to a specified file. If the file does not exist, the file is created and cleared before writing to the file
ReadDir() Read all subfiles and directory names in a directory
TempDir() In the current directory, create a temporary folder prefixed with the specified string name and return the folder path
TempFile() In the current directory, create a File prefixed with the specified string name and open it in read/write mode, returning a pointer to os.file
	data,error:=ioutil.ReadFile("./test1.csv")
	iferror! =nil{
		fmt.Printf("Opening error")}else {
		fmt.Println(string(data))
	}

	bs:=[]byte("Space open in Hello")
	error:=ioutil.WriteFile("./test1.csv",bs,077)
	iferror! =nil{
		fmt.Printf("Write file exception")}else {
		fmt.Printf("Write file successfully")}Copy the code

9.4 bufio package

Bufio implements buffered I/O operations for efficient read and write operations

  • Bufio. Reader structure

Common methods for bufio.reader

methods role
func NewReader(rd io.Reader) *Reader Create a * Reader with a default size buffer that reads from r
func NewReaderSize(rd io.Reader, size int) *Reader Create a * Reader from r with a size buffer
func (b *Reader) Discard(n int) (discarded int, err error) N bytes of data were discarded
func (b *Reader) Read(p []byte) (n int, err error) Read n bytes of data
func (b *Reader) Buffered() int Returns the number of bytes currently in the buffer that can be read
func (b *Reader) Peek(n int) ([]byte, error) Gets the next n bytes in the current buffer, but does not move the pointer
func (b *Reader) ReadByte() (byte, error) Read 1 byte
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) Read a line of data, \n delimited
func (b *Reader) ReadString(delim byte) (string, error) Read 1 string
func (b *Reader) ReadRune() (r rune, size int, err error) Read 1 UTF-8 character
func (b *Reader) Reset(r io.Reader) Clear buffer
  • Bufio. Writer structure

Chapter 10 Parallel programming

Concurrency and parallelism

  • Concurrency: Multiple tasks are executed at the same time

  • Parallelism: Perform multiple tasks at the same time

  • Concurrency in Go is implemented through Goroutines, which are similar to threads and belong to user-mode threads. We can create thousands of Goroutines to work concurrently on demand. Goroutine is scheduled by the Go language runtime, while threads are scheduled by the operating system.

  • The Go language also provides channels to communicate between multiple Goroutines. Goroutine and Channel are important implementations of the Go language’s concurrency pattern.

goroutine

  • The concept of a Goroutine is similar to a thread, but a Goroutine is scheduled and managed by the Go runtime. The Go program intelligently allocates the tasks in Goroutine to each CPU

  • In Go, you don’t need to write processes, threads, or coroutines. You only have one skill in your package — Goroutine. When you need to execute a task concurrently, you wrap that task into a function and start a Goroutine to execute that function

  • Using goroutine in the Go language is very simple. You simply add the Go keyword in front of the function being called, thus creating a Goroutine for a function (i.e. creating a thread).

  • A goroutine must correspond to a function, and multiple Goroutines can be created to perform the same function.

    Start a single Goroutine

    package main
    func t1Goroutine(a)  {
    	println("First Goroutine function")}func main(a) {
    	go t1Goroutine()
    	println("main over....")}T1Goroutine ????
    main over....
    
    Copy the code

    Reason: When the program starts, Go creates a default goroutine for the main() function.

    When main() returns, the goroutine ends, and all goroutines started in main() end with it. The goroutine in main is like the Night King in Game of Thrones, and all other goroutines are White Walkers. When the Night King dies, all the White Walkers he turned will be destroyed.

    So we’re going to have to figure out a way to make main wait and the simplest and most crude way to do hello is time.Sleep.

To execute the above code, print main over…. And then I print out the contents of the goroutine and the first goroutine function,

Why print main over…. in the first place This is because it takes some time to create a new goroutine, while the goroutine in which the main function is located continues execution

Start multiple Goroutines

package main
import (
	"fmt"
	"sync"
)
// The wait group is used to wait for the end of a set of goroutines, declared in the main Goroutine, and set the number of goroutines to wait, called Done for each Goroutine, and waited in the main goroutines
var wg sync.WaitGroup // Declare a global variable
func t2Goroutine(i int )  {
	defer wg.Done()
	fmt.Println("Go ", i)
}
func main(a) {
	for i:=0; i<10; i++{ wg.Add(1)
		go t2Goroutine(i)
	}
	wg.Wait()
}
// Output the result
Go  5
Go  1
Go  0
Go  7
Go  8
Go  2
Go  6
Go  9
Go  4
Go  3
Copy the code

If you execute the above code multiple times, you’ll see that the numbers are printed in an inconsistent order each time. This is because 10 Goroutines are executed concurrently, and goroutines are scheduled randomly.

Goroutine with thread

Growable stack

OS threads (operating system threads) typically have a fixed stack memory (usually 2MB). A Goroutine’s stack begins its life with a very small stack (typically 2KB). Goroutine’s stack is not fixed, it can be enlarged and shrunk as needed. Goroutine’s stack size can be limited to 1GB, although this size is rarely used. So it’s ok to create around 100,000 Goroutines at a time in Go.

Goroutine scheduling

GPM is the implementation of Go language runtime level and a scheduling system implemented by Go language itself. Different from operating system scheduling OS threads.

  • GIt is a goroutine, which contains information about the goroutine and its binding to the P.
  • PManages a set of Goroutine queues. P stores the context (function pointer, stack address, and address boundary) in which goroutine is currently running. P will perform some scheduling on its own goroutine queue (such as suspending the goroutine that occupies a long CPU time, running the subsequent goroutine, etc.). When its own queue is consumed, IT will fetch from the global queue. If the global queue is also consumed, it will grab tasks from other QUEUES of P.
  • M (machine)The Go runtime virtualizes the kernel thread of the operating system. M and the kernel thread are usually mapped one by one. A Groutine is eventually placed on M for execution.

P and M usually correspond one to one. Their relationship is: P manages a group of G mounted on M. When a G blocks on a M for a long time, the Runtime creates a new M, and the P where G blocks will mount other GS on the new M. Reclaim the old M when the old G is blocked or considered dead.

The number of P is set by runtime.GOMAXPROCS (maximum 256). After Go1.5, the default is the number of physical threads. Some P and M are added when concurrency is high, but not too much. Switching too often is not worth the cost.

In terms of thread scheduling alone, Go has an advantage over other languages in that OS threads are scheduled by the OS kernel, whereas Goroutine is scheduled by the Go runtime’s own scheduler, which uses a technique called M: N scheduling (multiplexing/scheduling m Goroutines to N OS threads). One big characteristic is goroutine scheduling is done under the user mode, does not involve frequent switching between kernel mode and user mode, including memory allocation and release, is at the user mode maintains a large memory pool, not directly call system malloc function (unless the memory pool needs to be changed), the cost is much lower than scheduling OS thread. On the other hand, it makes full use of multi-core hardware resources, approximately divides several Goroutines into physical threads, and the ultra-light weight of its own Goroutine ensures the performance of GO scheduling

GOMAXPROCS

The Go runtime scheduler uses the GOMAXPROCS parameter to determine how many OS threads are needed to execute the Go code simultaneously

Declare runtime.GOMAXPROCS(1) in main.

The channel tunnel

If a Goroutine is a concurrent implementation of the Go program, a channel is the connection between them. A channel is a communication mechanism that allows one Goroutine to send specific values to another goroutine

A channel is a special type in the Go language. A channel, like a conveyor belt or queue, always follows a First In First Out rule, ensuring the order In which data is sent and received. Each channel is a conduit of a concrete type, which requires the element type to be specified when declaring a channel.

  • Declaring a channel type

    var by1 []int // Declare a slice of type int
    var ch1 chan int // Declare a channel of type int
    Copy the code
  • The declared channel needs to be initialized using the make function.

// Initialize the channel
ch2:=make(chan int)
// Initialize chan with buffer
ch3:=make(chan string)
Copy the code

The channel operations

A channel has three operations: send, receive, and close.

Both send and receive use the <- symbol.

  • Now let’s define a channel with the following statement:
ch := make(chan int)
Copy the code
  • Sends a value to the channel

    ch<- 10// send data 10 to ch
    Copy the code
  • Receives values from a channel

data:= <-ch// Assign the value received from ch to the variable data
<-ch        // Accept the value from ch, ignoring the result
Copy the code

We close the channel by calling the built-in close function.

close(ch)
Copy the code

One thing to note about closing a channel is that you only need to close a channel if you notify the receiver goroutine that all data has been sent. Channels can be reclaimed by the garbage collection mechanism, which is not the same as closing files. Closing files after an operation is required, but closing channels is not required.

The closed channel has the following characteristics:

  1. Sending values to a closed channel can cause panic.
  2. Receiving on a closed channel fetches values until the channel is empty.
  3. A receive operation on a closed channel with no value results in a zero value of the corresponding type.
  4. Closing a closed channel can cause panic.

Unbuffered channels

Unbuffered channels are also called blocked channels

func main(a)  {
	// Initialize the channel
	ch1:=make(chan int)
	ch1 <- 10
	fmt.Printf("Sent successfully")}// Output the result
fatal error: all goroutines are asleep - deadlock!
goroutine 1 [chan send]:
main.main()
	D:/work/workspace/go_space/goruntine.go:8 +0x5f
Copy the code

Why did a deadlock error occur?

Because we use ch1 := make(chan int) to create unbuffered channels, unbuffered channels can only send values if someone receives them. Just like you live in a community where there is no delivery cabinet or collection point, the Courier must deliver this item to your hand when he calls you. Simply speaking, the unbuffered channel must have reception before it can be sent.

The above code blocks on the line ch < -10, resulting in a deadlock. How to solve this problem?

One way is to enable a goroutine to receive values, for example:

package main
import "fmt"
func recvData(c chan int)  {
	x:=<-c
	fmt.Println("Data received",x)
}
func main(a)  {
	// Initialize the channel
	ch1:=make(chan int)
	go recvData(ch1)
	ch1 <- 10
	fmt.Printf("Sent successfully")}// Output the resultReceived data10Send a successCopy the code

A send operation on an unbuffered channel blocks until another Goroutine performs a receive operation on that channel, at which point the value can be sent and both Goroutines continue to execute. Conversely, if the receive operation is performed first, the receiver’s Goroutine blocks until another Goroutine sends a value on that channel.

Communicating using an unbuffered channel results in synchronization of the goroutine that sends and receives. Therefore, unbuffered channels are also called synchronous channels

There are buffered channels

Another way to solve the above problem is to use channels with buffers

func main(a)  {
	// Initialize the channel
	ch1:=make(chan int ,2)
	ch1 <- 10
	fmt.Printf("Sent successfully")}Copy the code

Cyclic value from channel

When we have finished sending data to the channel, we can use the close function to close the channel.

package main

import (
	"fmt"
)
func main(a) {
	ch1:=make(chan int)
	ch2:=make(chan  int)
	// Loop to generate 100 numbers and store them in ch1
	go func(a) {
		for i:=0; i<10; i++{ ch1<-i }close(ch1)
	}()
	// Receive the value from ch1 and store it in CH2
	go func(a) {
		for{
			data,ok:=<-ch1 // Ok =false after the channel is closed
			if! ok{break
			}
			ch2<-data*data

		}
		close(ch2)
	}()
	// Range ch2 in main goroutine
	for i:=range ch2{// The channel closes and exits the for range loop
		fmt.Println(i)
	}
}
// Output the result
0
1
4
9
16
25
36
49
64
81
Copy the code

From the example above we can see that there are two ways to determine if the channel is closed when receiving a value, but we usually use the for range method. Use the for range to traverse the channel and exit the for range when the channel is closed

A one-way passage

  • chan<- intIs a write-only one-way channel (only int can be written to it) that can be sent but cannot be received.
  • <-chan intIs a read-only one-way channel (from which only int values can be read) that can be received but cannot be sent.

Chapter 11 Reflections

Reflection can integrate information about variables such as field names, types, and structs into executable files at compile time, so that reflection information about types can be retrieved at run time

The Go program uses the Reflect package at run time to access the program’s reflection information.

In the reflection mechanism of the Go language, any interface value consists of a concrete type and a concrete type value. In Go, reflection functions are provided by the built-in Reflect package. Any interface Value can be understood as reflect.Type and reflect.Value. The Reflect package provides two functions, reflect.TypeOf and reflect.ValueOf, to get the Value and Type of any object.

  • reflect.TypeOf()

    Gets an object of type with any value

func reflectType(x interface{}) {
	v := reflect.TypeOf(x)
	fmt.Printf("type:%v\n", v)
}
func main(a) {
	var a float32 = 3.14
	reflectType(a) // type:float32
	var b int64 = 100
	reflectType(b) // type:int64
}
Copy the code
  • Type name and type kind

There are also two types of reflection: Type and Kind. Because in Go we can use the type keyword to construct many custom types, and Kind refers to the underlying type, but in reflection, when we need to distinguish Pointers, constructs, and other large types of type, we use Kind. For example, we define two pointer types and two struct types and see their types and types through reflection.

Go language reflection in the array, slice, Map, pointer, and other types of variables, their. Name() returns null.

type person struct {
	Name string `json:"name"`
	Age int `json:"age"`

}
func reflectType(x interface{}) {
	v := reflect.TypeOf(x)
	fmt.Printf("type:%v kind:%v\n", v.Name(), v.Kind())
}
func main(a) {
	var a float32 = 3.14
	reflectType(a) // type:float32
	var b int64 = 100
	reflectType(b) // type:int64
	p:=person{
		"struc".20,
	}
	reflectType(p) //type:person kind:struct
    m:=make(map[int]string)
    reflectType(m) //type: kind:map
	var s []string
	reflectType(s) //type: kind:slice
}
Copy the code
  • reflect.ValueOf()

    Reflect.valueof () returns the reflect.value type, which contains the Value information of the original Value. Reflect. Value can be converted to and from the original Value.

func reValueOf(x interface{})  {
	v:=reflect.ValueOf(x)
	k:=v.Kind()
	switch k {
	case reflect.Int64:
		// v.nt () takes the original value of the integer from reflection and casts it through int64()
		fmt.Printf("type is int64, value is %d\n".int64(v.Int()))
	case reflect.Int32:
		fmt.Printf("type is int32, value is %d\n".int32(v.Int()))
	}
}
func main(a) {
	var b int64 = 100
	reValueOf(b) // type is int64, value is 100

}
Copy the code
  • Set variable values by reflection

If you want to change the value of a variable in a function through reflection, note that the function argument is passed as a copy of the value. You must pass the address of the variable to change the value. Reflection uses the proprietary Elem() method to retrieve the value of the pointer

func relectSetVal(x interface{})  {
	v:=reflect.ValueOf(x)
    // Use the Elem() method in reflection to get the value of the pointer
	if v.Elem().Kind()==reflect.Int64{
		v.Elem().SetInt(200)}}func main(a) {
	var b int64 = 100
	relectSetVal(&b)
	fmt.Println(b) / / 200
}
Copy the code
  • Structural reflection

    After any value is reflected through reflect.typeof (), the details of the members of the structure can be obtained through the NumField() and Field() methods of the reflect.type object if its Type is a structure.

type person struct {
	Name string `json:"name"`
	Age int `json:"age"`
}
func main(a) {
	p:=person{"test".20}
	r:=reflect.TypeOf(p)
	fmt.Println(r.NumField(),r.Name(),r.Kind()) //2 person struct
	// Kind is a struct
	if r.Kind()==reflect.Struct{
		// The for loop iterates through all the fields in the structure
		for i:=0; i<r.NumField(); i++{ field := r.Field(i) fmt.Printf("name:%s index:%d type:%v json tag:%v\n", field.Name, field.Index, field.Type, field.Tag.Get("json"))}}// Get the specified structure field information by field name
	if name_field,ok:=r.FieldByName("Name"); ok{ fmt.Printf("name:%s index:%d type:%v json tag:%v\n", name_field.Name, name_field.Index, name_field.Type, name_field.Tag.Get("json"))}}Copy the code

Chapter 12 Worker Pool (Goroutine Pool)

Chapter 13 network programming

A get request

func main(a) {
	resp, err := http.Get("http://www.baidu.com/")
	iferr ! =nil {
		fmt.Printf("get failed, err:%v\n", err)
		return
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	iferr ! =nil {
		fmt.Printf("read from resp.Body failed, err:%v\n", err)
		return
	}
	fmt.Println(string(body))
}
Copy the code

Get request with parameters

Parameters for GET requests need to be handled using the Go language’s built-in NET/URL library.

func httpGet2(requestUrl string) (err error) {
	Url, err := url.Parse(requestUrl)
	iferr ! =nil {
		fmt.Printf("requestUrl parse failed, err:[%s]", err.Error())
		return
	}

	params := url.Values{}
	params.Set("username"."googlesearch")
	params.Set("passwd"."golang")
	Url.RawQuery = params.Encode()
	requestUrl = Url.String()
	fmt.Printf("requestUrl:[%s]\n", requestUrl)
	resp, err := http.Get(requestUrl)
	iferr ! =nil {
		fmt.Printf("get request failed, err:[%s]", err.Error())
		return
	}
	defer resp.Body.Close()
	bodyContent, err := ioutil.ReadAll(resp.Body)
	fmt.Printf("resp status code:[%d]\n", resp.StatusCode)
	fmt.Printf("resp body data:[%s]\n".string(bodyContent))
	return
}
Copy the code

Post request with parameters

func httpPost(requestUrl string) (err error) {
	data := url.Values{}
	data.Add("username"."seemmo")
	data.Add("passwd"."da123qwe")

	resp, err := http.PostForm(requestUrl, data)
	iferr ! =nil {
		fmt.Printf("get request failed, err:[%s]", err.Error())
		return
	}
	defer resp.Body.Close()

	bodyContent, err := ioutil.ReadAll(resp.Body)
	fmt.Printf("resp status code:[%d]\n", resp.StatusCode)
	fmt.Printf("resp body data:[%s]\n".string(bodyContent))
	return
}
Copy the code

TCP Connection Procedure

TCP server program processing flow:1.Listen on port2.Receive a client request to establish a connection3.Create a Goroutine to handle the process of connecting to a TCP client:1.Establish a link to the server2.Data receiving and receiving3.Close linksCopy the code
  • Server code
package main
import (
	"bufio"
	"fmt"
	"net"
)

// Implement TCP communication steps:
//1. Listen to the port
//2. Receive the client request to establish a connection
//3. Create a goroutine to process the connection
func process(conn net.Conn) {
	defer  conn.Close() // Delay shutdown
	reader:=bufio.NewReader(conn)
	var b [128]byte
	for {
		n,err:=reader.Read(b[:])
		iferr! =nil{
			fmt.Println("read from client failed, err:", err)
			break
		}
		recvStr := string(b[:n])
		fmt.Println("Received data from client:", recvStr)
		conn.Write([]byte(recvStr)) // Send data}}func main(a) {
	listen,err:=net.Listen("tcp"."127.0.0.1:9090")
	iferr! =nil{
		fmt.Println("listen failed, err:", err)
		return
	}
	for{
		conn,err:=listen.Accept()
		iferr! =nil {
			fmt.Println("accept failed, err", err)
			continue
		}
		go process(conn)
	}

}
Copy the code
  • Client code

    package main
    
    import (
    	"bufio"
    	"fmt"
    	"net"
    	"os"
    	"strings"
    )
    
    func main(a) {
    	conn,err:=net.Dial("tcp"."127.0.0.1:9090")
    
    	iferr! =nil{
    		fmt.Println("err:",err)
    		return
    	}
    	defer conn.Close()
    	fmt.Println("Please enter data")
    	inputReder:=bufio.NewReader(os.Stdin)
    	for{
    		input,_:=inputReder.ReadString('\n')
    		inputInfo := strings.Trim(input, "\r\n")
    		if strings.ToUpper(inputInfo) == "Q" { // Exit if you enter q
    			return
    		}
    		_, err = conn.Write([]byte(inputInfo)) // Send data
    		iferr ! =nil {
    			return
    		}
    		buf := [512]byte{}
    		n, err := conn.Read(buf[:])
    		iferr ! =nil {
    			fmt.Println("recv failed, err:", err)
    			return
    		}
    		fmt.Println(string(buf[:n]))
    	}
    }
    Copy the code

Chapter 14 Database Operations

Download the dependent
go get -u github.com/go-sql-driver/mysql
Copy the code
Create dbconf package
package dbconf
import (
	"database/sql"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
)
// Define a global object db
var db *sql.DB
func InitDb(a) (err error)  {
	dsn := "Epai: epai @ TCP/bind_dns (10.10.10.48:3306)? charset=utf8mb4&parseTime=True"
	// The account password is not verified
	// Attention!! Instead of using :=, we assign to the global variable and then use db in main
	db,err = sql.Open("mysql", dsn)
	iferr ! =nil {
		return
	}
	// Try to establish connection with database (verify DSN is correct)
	err = db.Ping()
	iferr ! =nil {
		return
	}
	return
}
type binddns struct {
	zone string
	data string

}
func QueryRowDemo(a)  {
	var dns binddns
	sqlStr := "SELECT zone, data from dns_records"
	rows,err:=db.Query(sqlStr)
	defer rows.Close()
	iferr ! =nil {
		fmt.Printf("query failed, err:%v\n", err)
	}
	for rows.Next() {
		err:=rows.Scan(&dns.zone,&dns.data)
		iferr ! =nil{
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("Domain :%s Record value :%s\n", dns.zone,dns.data)
	}
}
func InserDemo(a) {
	sqlstr := INSERT INTO 'dns_records' VALUES (9, 'abc.com', '*', 'A', '10.10.10.83', 60, NULL, 'any', 255, 28800, 14400, 86400, 86400, 2015050917, 'ddns.net', 'ns.ddns.net.');"
	res, error := db.Exec(sqlstr)
	iferror ! =nil {
		fmt.Printf("insert failed, err:%v\n", error)
		return
	}
	theID, err := res.LastInsertId() // The ID of the newly inserted data
	iferr ! =nil {
		fmt.Printf("get lastinsert ID failed, err:%v\n", err)
		return
	}
	fmt.Printf("insert success, the id is %d.\n", theID)
}
func UpdateDemo(a) {
	sqlstr:="update dns_records set data=? where id = ?"
	res,err:=db.Exec(sqlstr,"10.10.10.98".9)
	iferr ! =nil{
		fmt.Printf("update failed, err:%v\n", err)
		return
	}
	res_row,err:=res.RowsAffected()
	iferr ! =nil{
		fmt.Printf("get RowsAffected failed, err:%v\n", err)
		return
	}
	fmt.Printf("update success, affected rows:%d\n", res_row)

}

Copy the code
Import the dbconf package in main.go
package main

import (
	"fmt"
	"test_go_mod2/dbconf"
)
func main(a) {

	err:=dbconf.InitDb()
	iferr ! =nil {
		fmt.Printf("init db failed,err:%v\n", err)
		return
	}else {
		fmt.Println(Mysql connection successful)
	}
	dbconf.QueryRowDemo()
	dbconf.InserDemo()
	dbconf.UpdateDemo()
}
Copy the code
pretreatment

Why preprocessing?

  1. By optimizing the MySQL server to execute SQL repeatedly, the server performance can be improved and the server can be compiled in advance. In this way, the cost of subsequent compilation can be saved.
  2. Avoid SQL injection problems.

The Prepare method sends the SQL statement to the MySQL server and returns a prepared state for subsequent queries and commands. The return value can execute multiple queries and commands simultaneously.

/ / query
func PreareDemo(a) {
	sqlStr := "SELECT zone, data from dns_records where id < ?"
	stmt,err:=db.Prepare(sqlStr)
	iferr ! =nil {
		fmt.Printf("preare query failed, err:%v\n", err)
	}
	rows,err:=stmt.Query(8)
	defer rows.Close()
	iferr ! =nil {
		fmt.Printf("query failed, err:%v\n", err)
	}
	for rows.Next() {
		err:=rows.Scan(&dns.zone,&dns.data)
		iferr ! =nil{
			fmt.Printf("scan failed, err:%v\n", err)
			return
		}
		fmt.Printf("Domain :%s Record value :%s\n", dns.zone,dns.data)
	}
}

Copy the code

Chapter 15 GORM Operations


Updates continue at.....

Regular syncing: personal website

More exciting public account “51 Operation and Maintenance com”