Golang quick start

Golang basic learning notes, quickly understand the basic grammar of golang.

Learning materials

1, Development environment configuration

The installation of golang is very simple. You can directly download the installation package of the corresponding system from the official website of golang and install it directly; However, the official website of golang: https://golang.org Unable to visit China due to special reasons; So use this: https://golang.google.cn/ .

The installation of windows and Mac can go all the way to next directly according to the installation interface; The only thing to pay attention to is the installation path. If you don't want to use the default, you can modify the installation path (Windows recommends changing a directory without spaces). After successful installation, enter go version to see the installed version. The MAC is installed in the / usr/local/go directory by default.

Due to domestic network reasons, some packages cannot be downloaded; Therefore, GOPROXY needs to be configured to solve the problem; That is, add GOPROXY configuration in the environment variable; Here are some available domestic source configurations:

  • Alibaba cloud https://mirrors.aliyun.com/goproxy/
go env -w GOPROXY=https://mirrors.aliyun.com/goproxy/
  • goproxy. Services provided by IO https://goproxy.io/zh/
# Configure GOPROXY environment variables
go env -w GOPROXY=https://goproxy.io,direct
# You can also set private warehouses or groups that do not use proxy, with multiple separated by commas (optional)
export GOPRIVATE=git.mycompany.com,github.com/my/private

2, Common commands

compile

go build go File name

# Custom generated exe file name
go build -o Custom name.exe go File name

# Examples
go build hello.go
go build main.go
go build -o hello.exe hello.go

Run program

go run hello.go

format file

gofmt -w hello.go

Run test

go test -v

View environment variable configuration

go env

View resource competition

go build -race demo.go

3, Basic grammar and concepts

This is basically not much different from other languages. The difference is that the definition of golang is to write the type behind the variable. At the same time, it does not support automatic type conversion and needs to be converted manually; Basic types included: bool, float32, float64, string, byte (uint8), int, int8, int16, int32, int64, rune (int32, commonly used to handle unicode or utf-8 characters); Other types of slices, structures, functions, interfaces, map s. At the same time, golang does not need to write symbols at the end of the statement.

matters needing attention

  • Case sensitive;
  • You can not write semicolon;
  • Defined or introduced must be used;
  • Under a folder There can only be one main function in the go file;
  • Implicit conversion is not supported; Conversion must be displayed;
  • Function does not support overloading
  • The addresses assigned to attributes in the structure are continuous
  • Structs are passed using values
  • When the structure is forced to convert, the properties of the two structures need to be the same

Define variables

The syntax is as follows. Note that golang will automatically set the initial value.

// Declare that the variable is not assigned, the default value will be used, and the default value of int is 0
var a int

// Declare variables and assign values
var b int = 10

// Simplify the writing of var keyword
c := 100

// Automatically judge the variable type according to the value
var d = 10

// Declare multiple variables of the same type at one time
var n1, n2, n3 int

// Declare multiple variables at one time, and the types are different
var age, nickName, addr = 10, "jerry", "Beijing"

// Declare multiple variables at one time, abbreviated as var keyword
email, phone, pwd := "1314@qq.com", 9580, "123456"

// When declaring multiple global variables, you can wrap them directly with a var
var (
    ok_status = "ok"
    ok_code = 200
)

// If the characters are in the ascii table, you can use byte directly
var ch byte = 'a'
fmt.Println(ch)
var ch2 int = 'Cattail'
fmt.Println(ch2)
fmt.Printf("%c", ch2)

// rune handles unicode or utf-8 characters; Because the string is stored in byte at the bottom, the Chinese problem can be solved through run
arr2 := []rune(str)
arr2[1] = 'Lee'
str = string(arr2)
fmt.Println("str=", str)

String considerations

Note that once the string is assigned, it cannot be modified. For example, the following is wrong

// The string cannot be modified after assignment
var str string = "help"
str[0] = 'a'

String splicing can be directly used with +; However, it should be noted that if golang needs line feed, + must be placed on the previous line; As follows:

// You need to put the plus sign behind
var str4 = "hello" +
 "word"
 fmt.Println(str4)

Definition of array

The size of the array must be set when it is defined; The types of arrays with different space sizes are different; Note: when passing an array in a function, the value is passed; Separate it from the slice.

var arr [6]int
arr[0] = 5

var arr1 [3]int = [3]int{1, 2, 3}
fmt.Println("arr1=", arr1)

var arr2 = [3]int{4, 5, 6}
fmt.Println("arr2=", arr2)

// there... It is a fixed writing method; The final size is determined by the number of initial values set later
var arr3 = [...]int{7, 8, 9}
fmt.Println("arr3=", arr3)

var arr4 = [...]int{1: 10, 0: 11, 2: 12}
fmt.Println("arr3=", arr4)

// Two dimensional array
var arr [6][6]int
arr[1][2] = 1

Definition of slice

The slice in golang can be simply regarded as a dynamically expanded array. The memory allocated by the slice at the bottom is continuous.

// The definition of slice is very similar to that of array, and the size is not specified
var slice []int
// Note that for slices without initial values, you must apply for space through the make method
slice = make([]int, 0)

// Slice with initial value
var slice2 []string = []string{"tom","jerry"}

// Intercept a piece of data from an array or slice
arr := [...]int{1, 2, 3, 4}
// [1:3] refers to the value of the subscripts 1 to 3 of the arr array (excluding 3)
slice := arr[1:4]
// [:] this means taking all; At the same time, slices can be sliced again
slice := arr[:]

// View the number of slice elements
fmt.Println("slice Number of elements:", len(slice))
// View slice capacity
fmt.Println("slice Capacity of", cap(slice))

// Add a new element to the slice
slice = append(slice, 40)
// Add multiple new elements to the slice
slice = append(slice, 50, 60, 70)

arr[1] = 100

Definition and use of function variables

The function of golang is also a variable, so the function can also be assigned to the variable; The writing method is actually very similar to the grammar of js. Here is an example:

package main

import (
	"fmt"
	"strings"
)

// accumulation
func AddUpper() func (int) int  {
	var n int = 0;
	return func (x int) int  {
		n = n+x;
		return n;
	}
}

// Determine whether suffix is included
func makeSuffix(suffix string) func (string) string {
	
	return func(name string) string {
		 if !strings.HasSuffix(name, suffix) {
			 return name + suffix
		 }
		 return name
	}
}

func main()  {
	// Assign AddUpper function to variable f; It can be called through f (a bit like taking an alias)
	f := AddUpper()
	fmt.Println(f(1))

	suffix := makeSuffix(".jpg")
	fmt.Println(suffix("1.png"))
	fmt.Println(suffix("1.jpg"))
}

map

// Declaration map
var a map[string]string

// The initial map space needs to be allocated manually
a = make(map[string]string, 2)

// assignment 
a["no1"] = "Zhang San"


// Allocate space when defining
var map2 = make(map[string]string, 10)
map2["s1"] = "100"
fmt.Println(map2)

// Assign value when defining
map3 := map[string]string {
    "address":"Chengdu",
}
fmt.Println(map3)

// Structure of map < string, Map >
map4 := make(map[string]map[string]string, 2)
map4["001"] = make(map[string]string, 1)
map4["001"]["name"] = "jerry"
map4["001"]["age"] = "26"
map4["002"] = map3
fmt.Println(map4)

// Delete values in map
delete(map4, "002")

// If you want to delete all key s, you need to traverse one by one to delete them; Or reopen a space
for k, _ := range map4 {
    delete(map4, k)
}
// Reopen a space
map4 = make(map[string]map[string]string)

// For the search of map, the key exists and ex is true
val, ex := map3["address"]
fmt.Println(val, ex)

// Use of map slices
var map5 []map[string]string
map5 = make([]map[string]string, 2)

// It is not recommended to use specific array subscripts here, because it is easy to cross the boundary
if map5[0] == nil {
    map5[0] = make(map[string]string, 2)
    map5[0]["name"] = "Tang Monk"
    map5[0]["store"] = "1000"
}
// Corresponding to the dynamic increase, the following method is recommended
newMap := map[string]string {
    "name":"Wujing",
    "store": "5000",
}
map5 = append(map5, newMap)
fmt.Println(map5)

// Traversal of map
for k, v := range map6 {
    fmt.Println(k, "--", v)
}

// map sorting
map6 := map[int]int{1:1, 2:2, 4:4, 3:3,}
var keys []int
for k, _ := range map6 {keys = append(keys, k)}
for k, v := range map6 {fmt.Println(k, "--", v)}
sort.Ints(keys)
fmt.Println(keys)

structural morphology

type Person struct {
    Name string
    Age int
}

// use
p2 := Person{"jerry", 26}

// To define a pointer class
var p3 *Person = new(Person)
(*p3).Name = "tom"
// The designers of golang can write this directly for the convenience of developers
p3.Age = 26
fmt.Println(*p3)

// To define a pointer class
var p4 *Person = &Person{}
(*p4).Name = "tj"
// The designers of golang can write this directly for the convenience of developers
p4.Age = 0
fmt.Println(*p4)

// Define the simplified writing method of pointer class
p5 := &Person{Name: "jerry", Age: 100}
p5.Age = 26
fmt.Println(p5)

// Set alias when serializing json
type Message struct {
    Type string `json:"type"`
    Data string `json:"data"`
}

Type conversion

golang does not support implicit conversion; Conversion must be displayed.

var a int = 100
var b float32 = float32(100)

var c int = 100
var d int32 = int32(100)

Based on FMT The sprintf method implements type conversion

var str string

// int to string
var num1 int = 99
str = fmt.Sprintf("%d", num1)
fmt.Println(str)

// float to string
var num2 float64 = 23.456
str = fmt.Sprintf("%f", num2)
fmt.Println(str)

// bool to string
var b bool = true
str = fmt.Sprintf("%t", b)
fmt.Println(str)

// byte to string
var myChar byte = 'h'
str = fmt.Sprintf("%c", myChar)
fmt.Println(str)
fmt.Printf("str type %T, str=%q", str, str)

// byte array to string
arr1 := []byte(str)
arr1[0] = 'z'
str = string(arr1)
fmt.Println("str=", str)

Implementation of type conversion based on strconv function

var num4 int = 99
// FormatInt(int64, binary (2-binary, 10 decimal))
str = strconv.FormatInt(int64(num4), 10)
fmt.Println(str)

// f: Decimal format, 10 decimal, 64 float64
var num5 float64 = 236.5432
str = strconv.FormatFloat(num5, 'f', 10, 64)
fmt.Println(str)

// Convert to bool
str = strconv.FormatBool(b2)
fmt.Println(str)
// Convert string to bool
b2, _ = strconv.ParseBool(str)

Conversion of slice and string

// Cutting a part of a string; This is not recommended for strings with Chinese characters, which may cause garbled code
str := "h Zhang San llo@golang.com"
slice := str[6:]
fmt.Println("slice=", slice)

// byte slice to string
arr1 := []byte(str)
arr1[0] = 'z'
str = string(arr1)
fmt.Println("str=", str)

// Since the second digit is Chinese, and the byte stored in Chinese is more than one digit, there will be garbled code
arr1 = []byte(str)
arr1[1] = 'z'
str = string(arr1)
fmt.Println("str=", str)

// Run slice to string; This rune can solve the problem of Chinese garbled code
arr2 := []rune(str)
arr2[1] = 'Lee'
str = string(arr2)
fmt.Println("str=", str)

Input / output statement

The input and output statements of golang and the formatted are all dependent on fmt.

Output statement

// Output specified characters
fmt.Println("full name\t Age\t address")
// Output multiple values
fmt.Println("Value 1", "Value 2")

// View variable types
var n = 100
fmt.Printf("n The type of is %T \n", n)

// View the number of bytes occupied by the variable and its type
var n2 int64 = 10000
fmt.Printf("n2 The type of is %T The number of bytes occupied is %d", n2, unsafe.Sizeof(n2))

// Use English ` ` to realize as is output
str1 := `
		In the Quiet Night
			 Li Bai
	The bright moon in front of the bed is suspected to be frost on the ground.
	Raising my head, I see the moon so bright; withdrawing my eyes, my nostalgia comes around.		 
	`
fmt.Println(str1)

// %v means output as is; Data type conversions must display conversions
var i1 int32 = 100
var f1 float32 = float32(i)
var i2 int8 = int8(i1)
fmt.Printf("i=%v, f=%v, i2=%v, f=%f", i1, f1, i2, f1)

Input statement

var name string
var age byte
var store float32
var isPass bool

fmt.Print("Please enter your name:")
// Pointers must be used here
fmt.Scanln(&name)

// Qualified input type
fmt.Scanf("%s %d %f %t", &name, &age, &store, &isPass)

Logical judgment and circular statement

Golang only has for and switch, not while; The only difference between conditional judgment statements and if is that there is no need to write parentheses in golang;

for loop

// Ordinary use
for i := 1; i<10; i++ {
    fmt.Printf("This is the second%v individual\n", i)
}

// Write only conditions; Achieve an effect similar to while
var j = 10;
for j>0 {
    fmt.Printf("this is %v\n", j)
    j--
}

// No conditions are written. There is an opportunity for internal judgment to jump out of the cycle
for { // This is equivalent to for; {}
    fmt.Printf("this is %v\n", j)
    if(j<1){
    	// Jump out of loop
        break
    }
}

// Traverse characters in string
var str string = "ancde chinese"
// In the traditional way, if there is Chinese in the string, there will be problems
for i := 0; i<len(str); i++ {
    fmt.Printf("%c ", str[i])
}

// Use for range to traverse the string
for index, val := range str {
    fmt.Printf("%d %c ", index, val)
}

// Traditional ways to solve Chinese problems
str2 := []rune(str)
for i := 0; i<len(str2); i++ {
    fmt.Printf("%c ", str2[i])
}

switch Statements

The switch statement of golang supports multiple values in a case, so there is no need to write break; Then, expressions are allowed in case, and the following is an example.

Traditional writing

a := 100
switch a {
  case 100:
    // Note that break will be added automatically
    fmt.Println("A")
  case 96, 97, 98, 99
    fmt.Println("B")
  default:
    fmt.Println("C")
}

How to use expressions

a := 100
switch {
  case a==100:
    // Note that break will be added automatically
    fmt.Println("A")
  case a > 95
    fmt.Println("B")
  default:
    fmt.Println("C")
}

Definition of function

In golang, the whole program can only have one main function. The defined package is similar to the class name in Java. When calling methods in other files, you need to introduce package, and then pass the package name Method name; In golang, the first letter of the method name is lowercase, which means that you can only access it in the current package; The initial size indicates that it can be called in other packages. The syntax of function definition is as follows:

// Functions without parameters and return values
func methodName1(){
    fmt.Println("Execute related logic")
}

// Functions with parameters
func methodName2(val int){
    fmt.Println("Execute related logic")
}

// Functions with parameters and return values
func methodName3(val int) int {
    fmt.Println("Execute related logic")
    return val+1
}

// Functions with parameters and return values; The name of the return value is defined here. Return will return automatically
func methodName4(val int) (res int) {
    fmt.Println("Execute related logic")
    res = val+1
    return
}

// Functions with parameters and return values; Return multiple parameters
func methodName5(val int) (res int, err error) {
    fmt.Println("Execute related logic")
    res = val+1
    return
}

// Variable parameter
func sum(sum int, args... int) int {
    for i := 0; i<len(args); i++ {
        sum += args[i]
    }
    return sum
}

// Anonymous function
res2 := func (n1 int, n2 int) int {
        return n1+n2
    }(1, 3)
fmt.Println(res2)


// Custom type
type customizeFun func(int , int) int
// The function whose parameter contains the function;
func methodName6(fun customizeFun, num1 int, num2 int) int  {
    return fun(num1, num2)
}
// Call example; Assign a function to a variable, which means that a function is also a type
ca := Sum
fmt.Println(ca(a, b))
func Sum(a int, b int) int  {
    return a+b
}

// Structure binding method
type Person struct {
    Name string
    Age int
}
// The structure is automatically bound to this method
func (p *Person) getBirthYear() {
    var year = 2021-p.Age
    fmt.Println(year)
}
// The structure is automatically bound to this method
func (p Person) getBirthYear() {
    var year = 2021-p.Age
    fmt.Println(year)
}

defer

If the statement modified by defer is not executed temporarily, the statement behind it will be pushed into an independent stack; After the function is executed, it will be executed from the defer stack in a first in first out manner.

func sum(n1 int, n2 int) int {
	// When defer is executed, it will not be executed temporarily, and the statements behind it will be pushed into a separate stack
	// After the function is executed, it will be executed from the defer stack in a first in first out manner
	defer fmt.Println("ok1, n1=", n1)
	defer fmt.Println("ok2, n2=", n2)
	
	n1++
	res := n1 + n2
	fmt.Println("ok3, res=", res)
	return res
}

Definition of interface

The interface of golang has no constraints on the implementation. The interface is more like a method specification definition. The following is a scenario example of a USB interface:

// Define interface
type Usb interface {
	Start()
	Stop()
}

type Phone struct {
}

func (p *Phone) Start()  {
	fmt.Println("Mobile phone starts successfully")
}
func (p *Phone) Stop()  {
	fmt.Println("Mobile phone stopped successfully")
}

func connect(usb Usb)  {
	usb.Start()
}

func main()  {
	var p = &Phone{}
	connect(p)
}

exception handling

The exception thrown by the function can be recovered through recover; It is generally used in conjunction with defer.

Abnormal recover y

func demo()  {
	// Use recover to catch exceptions through defer
	defer func() {
		err := recover()
		if err != nil {
			fmt.Println("err=", err)
		}
	}()

	a := 10
	b := 0
	// An error will be reported here
	res := a / b
	fmt.Println("res=", res)
}

errors custom exception

func readConf(name string) (err error) {
	if name == "config.ini" {
		return nil
	}
	// Create exception
	return errors.New("fail to read file")
}

panic throws an exception

err := readConf("config.ini")
if err != nil {
    // Throw exception
    panic(err)
}
fmt.Println("ok")

4, File IO stream operation

bufio, IO, io/ioutil and os packages are mainly used for file IO related operations.

Open file

// Open file
file, err := os.Open("/doc/addGoPath.bat")
if err != nil {
    fmt.Println("open file err=", err)
}

// The file here is a pointer
fmt.Println("file=%v", file)

// Close file
err = file.Close()
if err != nil {
    fmt.Println("close file err=", err)
}

read file

Read file from buffer

file, err :=  os.Open("/doc/addGoPath.bat)
if err != nil {
    fmt.Println("open file err=", err)
}
defer file.Close()

// The buffer size returned by NewReader is 4096
reader := bufio.NewReader(file)
for {
    // It ends when you read a line feed
    str, err := reader.ReadString('\n')
    if err == io.EOF {
        // io.EOF indicates the end of the file
        break
    }
    fmt.Println(str)
}

Read all contents of the file at one time

If the file content is small, you can choose to read all at once.

path := "/doc/addGoPath.bat"
// The content returned here is a slice
content, err := ioutil.ReadFile(path)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}

fmt.Printf("%v", string(content))

Create files and write data

fileName := "/doc/demo4.txt"
// Description of corresponding parameters: file name, read operation configuration, permissions (only effective under linux and Unix Systems)
file, err := os.OpenFile(fileName, os.O_WRONLY | os.O_CREATE, 0666)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}
str := "hello, golang\r\n"
// Get write cache
writer := bufio.NewWriter(file)

for i := 0; i<5; i++ {
    // Note that this is a direct overwrite write
    writer.WriteString(str)
}

// Because the cache is used, you need to call the refresh function to refresh it to the disk
writer.Flush()

Write data

Write data is divided into overwrite write and append write.

Write data (overwritten write)

fileName := "/doc/demo4.txt"
// Parameters: file name, read operation configuration, permissions (only effective under linux and Unix Systems), O_ Write of TRUNC overlay
file, err := os.OpenFile(fileName, os.O_WRONLY | os.O_TRUNC, 0666)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}
str := "hello, golang\r\n"
// Get write cache
writer := bufio.NewWriter(file)

for i := 0; i<5; i++ {
    // Note that this is a direct overwrite write
    writer.WriteString(str)
}

// Because the cache is used, you need to call the refresh function to refresh it to the disk
writer.Flush()

Write data (additional write)

fileName := "/doc/demo4.txt"
// Parameters: file name, read operation configuration, permissions (only effective under linux and Unix Systems), O_TRUNC appended write
file, err := os.OpenFile(fileName, os.O_WRONLY | os.O_APPEND, 0666)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}
str := "Something\r\n"
// Get write cache
writer := bufio.NewWriter(file)

for i := 0; i<5; i++ {
    // Note that this is a direct overwrite write
    writer.WriteString(str)
}

// Because the cache is used, you need to call the refresh function to refresh it to the disk
writer.Flush()

Read write mode (additional write)

fileName := "/doc/demo4.txt"
// Parameters: file name, read operation configuration, permissions (only effective under linux and Unix Systems), O_RDWR read / write mode, O_TRUNC appended write
file, err := os.OpenFile(fileName, os.O_RDWR | os.O_APPEND, 0666)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}

defer file.Close()

reader := bufio.NewReader(file)
for {
    str, err := reader.ReadString('\n')
    if err == io.EOF {
        break
    }
    fmt.Print(str)
}

str := "Something\r\n"
// Get write cache
writer := bufio.NewWriter(file)

for i := 0; i<5; i++ {
    // Note that this is a direct overwrite write
    writer.WriteString(str)
}

// Because the cache is used, you need to call the refresh function to refresh it to the disk
writer.Flush()

Use of ioutil tool class

read file

path := "/doc/demo4.txt"
data, err := ioutil.ReadFile(path)
if err != nil {
    fmt.Printf("read file err=%v\n", err)
    return
}

write file

path := "/doc/demo4.txt"

// Parameters: file path, data, permission
err = ioutil.WriteFile(path, data, 0666)
if err != nil {
    fmt.Printf("write file err=%v\n", err)
    return
}

File copy

func CopyFile(srcFileName string, targetFileName string) (writer int64, err error) {

	srcFile, err := os.Open(srcFileName)
	if err !=nil {
		fmt.Printf("open file err=%v", err)
		return
	}
	defer srcFile.Close()

	reader := bufio.NewReader(srcFile)

	targetFile, err := os.OpenFile(targetFileName, os.O_WRONLY | os.O_CREATE,  0666)
	if err != nil {
		fmt.Printf("open file err=%v", err)
		return
	}
	defer targetFile.Close()

	wr := bufio.NewWriter(targetFile)
	defer wr.Flush()

	return io.Copy(wr, reader)
}

5, Get system level information

View the number of CPU cores

cpuNum := runtime.NumCPU()
fmt.Println("CPU Number:", cpuNum)
// To set the number of CPU s to be used, you need to manually set them before version 8, and then you don't need to set them later
runtime.GOMAXPROCS(cpuNum)

Get parameters from the command line

fmt.Println("The parameters on the command line are", len(os.Args))
for i, v := range os.Args {
    fmt.Printf("args[%v]=%v\n", i, v)
}

//  go run 024.go -pwd 23456 -port 8087; Note that it must be the command written below, otherwise an error will be reported
// Read command line information using flag Toolkit
var pwd string
flag.StringVar(&pwd, "pwd", "123456", "This is a description")

var port int
flag.IntVar(&port, "port", 8080, "Port number, the default is 8080")

// This method must be called to convert the data
flag.Parse()
fmt.Println("pwd=", pwd)
fmt.Println("port=", port)

6, Deserialization and deserialization

serialize

Structure serialization

type Monster struct {
	Name string `json:"name"`
	Age int `json:"age"`
	Birthday string `json:"birthday"`
	Sal float64 `json:"sal"`
	Skill string `json:"skill"`
}

func structToJsonString() {
    monster := Monster{
        Name: "Ox demon king",
        Age: 500,
        Birthday: "1521-01-01",
        Sal: 8000000.00,
        Skill: "Ox devil fist",
    }
    
    data, err := json.Marshal(&monster)
    if err !=nil {
        fmt.Printf("Serialization error err=%v\n", err)
        return
    }
    fmt.Printf(string(data))
}

map serialization

func mapToJsonString() {
	monsterMap := make(map[string]interface{}, 1)
	monsterMap["name"] = "Yellow eyebrow King"
	monsterMap["age"] = 1000
	monsterMap["birthday"] = "1021-01-01"
	monsterMap["sal"] = 800000000.00
	monsterMap["skill"] = "Purple gold bowl"

	data, err := json.Marshal(monsterMap)
	if err !=nil {
		fmt.Printf("Serialization error err=%v\n", err)
		return
	}
	fmt.Printf(string(data))
}

Slice serialization

func sliceToJsonString()  {
	var slice []map[string]interface{}
	slice = make([]map[string]interface{},0)

	m := make(map[string]interface{},1)
	m["name"] = "Red boy"
	m["age"] = 200
	m["birthday"] = "1821-01-01"
	m["sal"] = 80000.00
	m["skill"] = "Samadhi true fire"

	slice = append(slice, m)

	data, err := json.Marshal(slice)
	if err != nil {
		fmt.Printf("Serialization error err=%v\n", err)
		return
	}
	fmt.Println(string(data))
}

Deserialization

Structure deserialization

type Student struct {
	Name string `json:"name"`
	Age int `json:"age"`
}
func jsonToStrut() {

	str := "{\"name\":\"Zhang San\", \"age\":26}"

	var stu Student
	err := json.Unmarshal([]byte(str), &stu)
	if err != nil {
		fmt.Printf("Deserialization error err=%v", err)
		return
	}
	fmt.Println(stu)
}

map deserialization

func jsonToMap() {
	str := "{\"name\":\"Zhang San\", \"age\":26}"
	var stu map[string]interface{}
	err := json.Unmarshal([]byte(str), &stu)
	if err != nil {
		fmt.Printf("Deserialization error err=%v", err)
		return
	}
	fmt.Println(stu)
}

Slice deserialization

func jsonToSlice() {
	str := "[{\"name\":\"Zhang San\", \"age\":26}]"
	var stu []map[string]interface{}
	err := json.Unmarshal([]byte(str), &stu)
	if err != nil {
		fmt.Printf("Deserialization error err=%v", err)
		return
	}
	fmt.Println(stu)
}

7, Unit test

Functions to be tested

func addUpper(n int) int {
	res := 0
	for i := 1; i<= n; i++ {
		res += i
	}
	return res
}

Unit Test documents; Note that the name of this file must be_ Only the end of Test can be recognized; The function name must start with Test, followed by Xxx; That is, the first X must be a capital letter;

func TestAddUpper(t *testing.T) {
	// Call the method to be tested
	res := addUpper(10)
	if res != 55 {
		// Output the error log and terminate the program
		t.Fatalf("Actual results=%v Does not match expectation 55", res)
	}
	// If the execution result is correct, the log will be output
	t.Logf("Correct execution...")
}

Sometimes we need to perform some initialization operations before function execution, so we can add the following methods to the test class

// This method will be executed first when running the test command
func TestMain(m *testing.M) {
    MysqlInit()
    // Call m.Run() to start executing the test
    m.Run()
}
func TestAddUpper(t *testing.T) {
    // Call the method to be tested
    res := addUpper(10)
    if res != 55 {
        // Output the error log and terminate the program
        t.Fatalf("Actual results=%v Does not match expectation 55", res)
    }
    // If the execution result is correct, the log will be output
    t.Logf("Correct execution...")
}

Use sub test method

// Main test function
func TestMember(t *testing.T) {
	// Execute sub test function
	t.Run("Test add user", testAddMember)
}

func testAddMember(t *testing.T){
	member := &Member{Name: "Zhang San", Password: "123456"}
	member.AddMember()
}

8, Synergetic process

golang's co process can be regarded as asynchronous execution in Java;

func demo() {
	for i := 1; i< 10 ;i++ {
		fmt.Println("hello world " + strconv.Itoa(i))
		time.Sleep(1000)
	}
}

func main() {
	// Start a collaborative process through the go keyword
	go demo()

	for i := 1; i< 10 ;i++ {
		// strconv. The itoa() function converts a number into a string, which can avoid the number being converted according to ascii code
		fmt.Println("main() hello golang  " + strconv.Itoa(i))
		time.Sleep(1000)
	}
}

9, Lock

The factorial of each number from 1 to 20 is calculated based on the coprocessor

var (
	factorialMap = make(map[int]int, 10)
	// Declare a global mutex
	// lock is a global mutex
	// sync is a package: synchronized
	// Mutex: it's mutual exclusion
	lock sync.Mutex
)

func cal(n int) {
	res := 1
	for i := 1; i<= n; i++ {
		res *= i
	}
	// Lock
	lock.Lock()
	factorialMap[n] = res
	// Unlock
	lock.Unlock()
}

func main() {

	for i := 1; i <= 20; i++ {
		// Open 20 co processes to calculate
		go cal(i)
	}

	// Locking is also required here, otherwise there will be resource competition
	time.Sleep(10)
	// Print results
	lock.Lock()
	for i, v := range factorialMap {
		fmt.Printf("%v: %v\n", i, v)
	}
	lock.Unlock()
}

10, Pipeline

Pipe chan: This is a queue

// chan is the import type, that is, the address is stored
var intChan chan int
intChan = make(chan int, 3)
fmt.Printf("intChan Value of=%v intChan Own address=%p\n", intChan, &intChan)

// Write data to pipeline
intChan<- 10
num := 211
intChan<- num
// Note: the total number of data written to the pipeline cannot exceed cap (capacity); Otherwise, an error will be reported
// Print pipe length and cap (capacity)
fmt.Printf("channel len=%v cap=%v", len(intChan), cap(intChan))

// Take out data from the pipeline; Note: if there is no data in the pipeline, a deadlock error will appear when taking values again
var num2 int
num2 = <-intChan
fmt.Println(num2)
fmt.Printf("channel len=%v cap=%v", len(intChan), cap(intChan))

// Pipeline traversal
close(intChan) // After the pipeline is closed, it can only be read and cannot be written; The pipeline must be closed when traversing again
for v := range intChan {
    fmt.Println(v)
}

Declare pipeline read-only and write only

// Pipeline declared write only
var chan1 chan<- int
chan1 = make(chan int, 3)
chan1<- 20
// num :=  <-chan1

// Declared read-only
var chan2 <-chan int
chan2 = make(chan int, 3)
num := <-chan2
fmt.Println(num)

Data reading and writing between processes based on pipeline

func writeData(intChan chan int) {
	for i := 1; i <= 50; i++ {
		intChan<- i
		fmt.Println("Write data ", i)
		time.Sleep(time.Second)
	}
	close(intChan)
}

func readChan(intChan chan int, exitChan chan bool) {
	for {
		v, ok := <-intChan
		if !ok {
			break
		}
		fmt.Printf("Read data=%v\n", v)
		time.Sleep(time.Second)
	}
	exitChan<- true
	close(exitChan)
}

// It should be noted that for the pipeline, there must be reading and writing, and the speed can be inconsistent; Otherwise, a blocking deadlock will occur.
func main() {

	intChan := make(chan int, 50)
	exitChan := make(chan bool, 1)
	go writeData(intChan)
	go readChan(intChan, exitChan)

	for {
		_, ok := <-exitChan
		if !ok {
			break
		}
	}
}

Use examples of pipes and processes

// Put data into management
func putNum(intChan chan int) {
	for i := 1; i <= 80; i++ {
		intChan<- i
	}
	close(intChan)
}

// Find prime
func primeNum(intChan chan int, primeChan chan int, exitChan chan bool) {
	var flag bool
	for {
		num, ok := <-intChan
		if !ok {
			break
		}

		flag = true
		for i := 2; i < num; i++ {
			if num % i == 0 {
				flag = false
			}
		}

		if flag {
			primeChan<- num
		}
	}
	fmt.Println("No data available, exit....")
	exitChan<- true
}


func main() {

	intChan := make(chan int, 1000)
	primeChan := make(chan int, 2000)
	exitChan := make(chan bool, 4)

	go putNum(intChan)

	for i := 1; i <= 4; i++ {
		go primeNum(intChan, primeChan, exitChan)
	}

	go func() {
		for i := 0; i< 4; i++ {
			// When there is no data, it will block here
			<-exitChan
		}
		close(primeChan)
	}()

	for {
		res, ok := <-primeChan
		if !ok {
			break
		}
		fmt.Printf("%v\n", res)
	}

}

####select reads pipeline data in a non blocking manner

When we are not sure when to close the pipeline, we can solve it by using select

intChan := make(chan int, 10)
for i := 0; i < 10; i++ {
    intChan<- i
}

strChan := make(chan string, 5)
for i := 0; i < 5; i++ {
    strChan<- "hello" + fmt.Sprintf("%d", i)
}

//label:
for {
    // Using select can solve the problem that we can't decide when to close the pipeline
    select {
        case v := <-intChan : // Note: if the pipeline has not been closed, it will not be blocked here all the time
            fmt.Printf("from intChan Read data:%d\n", v)
        case v := <-strChan :
            fmt.Printf("from strChan Read data%s\n", v)
        default:
            fmt.Println("No qualified, quit....")
            return
            //break label
    }
}

Solve the problem that the whole program crashes due to a panic exception in a co process

func sayHello() {
	for i := 0; i < 10; i++ {
		time.Sleep(time.Second)
		fmt.Println("hello world")
	}
}

func sayGolang(){
	// Recovery anomaly
	defer func() {
		if err := recover(); err != nil {
			fmt.Println("sayGolang() abnormal", err)
		}
	}()
	var m map[int]string
	m[0] = "golang"
}

func main() {
	go sayHello()
	go sayGolang()
	for i := 0; i< 10; i++ {
		fmt.Println("main() ok=", i)
	}
}

11, Reflection

Common type reflection

func reflectDemo(b interface{}) {

	// Get the type of variable through reflection
	rType := reflect.TypeOf(b)
	fmt.Println("rType=", rType)

	// Get reflect through reflection value
	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal=%v, type=%T\n", rVal, rVal)

	num1 := rVal.Int() + 10
	fmt.Println("num1=", num1)

	// Convert it back to interface {}
	iV := rVal.Interface()
	num2 := iV.(int)
	fmt.Printf("num2=%v, num2=%T\n", num2, num2)
}

var num int = 100
reflectDemo(num)

Structural reflection

type Student struct {
	Name string
	Age  int
}

func reflectStu(b interface{}) {

	rType := reflect.TypeOf(b)
	fmt.Println("rType=", rType)

	rVal := reflect.ValueOf(b)
	fmt.Printf("rVal=%v, type=%T\n", rVal, rVal)

	iV := rVal.Interface()
	stu := iV.(Student)
	fmt.Printf("num2=%v, num2=%T\n", stu, stu)
}

12, Programming network

websocket

Server example

func process(con net.Conn) {
	defer con.Close()
	for {
		// Create a slice
		buf := make([]byte, 1024)
		// Waiting for the client to send data
		n, err := con.Read(buf)
		if err != nil {
			fmt.Println("Receiving client data exception: ", err)
			return
		}
		fmt.Print(string(buf[:n]))
	}
}

func main() {
	fmt.Println("Service startup in progress...")
	// This indicates that TCP protocol is used to listen to 8888 port on the local
	//net.Listen("tcp", "127.0.0.1:8888")
	// Here, identify the 8888 port that uses TCP protocol to listen
	listen, err := net.Listen("tcp", "0.0.0.0:8888")

	if err != nil {
		fmt.Println("Service startup failed", err)
		return
	}
	fmt.Println("Service started successfully...")

	// Delay off
	defer listen.Close()

	// Polling waiting for connection
	for {
		// Wait for link
		con, err := listen.Accept()
		if err != nil {
			fmt.Println("Connection exception...")
		} else {
			fmt.Printf("Connection received from client:%v\n", con.RemoteAddr().String())
			go process(con)
		}
	}
}

Client example

func main() {
	con, err := net.Dial("tcp", "127.0.0.1:8888")
	if err != nil {
		fmt.Println("connection failed")
		return
	}
	// Stdin: standard input
	reader := bufio.NewReader(os.Stdin)
	line, err := reader.ReadString('\n')
	if err != nil {
		fmt.Println("Get input information exception")
		return
	}

	// send data
	n, err := con.Write([]byte(line))
	if err != nil {
		fmt.Println("Data sending exception:", err)
		return
	}
	fmt.Println("Send packet size:", n)
}

HTTP network

The simplest way to write

// Processing method after the request comes
func handler(w http.ResponseWriter, r *http.Request) {
	res := "welcome use grpc"
	url := r.URL.Path
	if "/api" == url {
		res = "api server is ok"
	}

	_, err := fmt.Fprintln(w, res, r.URL.Path)
	if err != nil {
		fmt.Println("response error:", err)
	}
}

func main() {

	// Configure route listening
	http.HandleFunc("/", handler)
	// Start the service and listen on port 8081
	err := http.ListenAndServe(":8081", nil)
	if err != nil {
		fmt.Println("Service startup failed")
	}
}

Custom handler

To customize the implementation of handler, you need to implement the serverhttp (responsewriter, * request) method of the handler interface

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}
type CustomHandler struct {

}

// Custom handler processor
func (c *CustomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
	_, err := fmt.Fprintln(w, "this is custom handler")
	if err != nil {
		fmt.Println("response error ", err)
	}
}

func main()  {

	handler := &CustomHandler{}
	// Configure the path and set the request handler
	http.Handle("/", handler)
	err := http.ListenAndServe(":8081", nil)
	if err != nil {
		fmt.Println("server start fail, error ", err)
	}
}

Customize the detailed configuration of the server

type CustomHandler struct {

}

// Custom handler processor
func (c *CustomHandler) ServeHTTP(w http.ResponseWriter, r *http.Request){
	_, err := fmt.Fprintln(w, "this is custom handler")
	if err != nil {
		fmt.Println("response error ", err)
	}
}

func main()  {

	server := http.Server{
		Addr: ":8081",
		Handler: &CustomHandler{},
		ReadHeaderTimeout: 2*time.Second,
	}

	err := server.ListenAndServe()
	if err != nil {
		fmt.Println("server start fail")
	}
}

Manually create Multiplexers

func main()  {

	http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
		_, err := fmt.Fprintln(w, "this is custom handler")
		if err != nil {
			fmt.Println("response error ", err)
		}
	})
	// Create multiplexers manually
	mux := http.NewServeMux()
	err := http.ListenAndServe("8081", mux)
	if err != nil {
		fmt.Println("server start error ", err)
	}
}

Get request content

func handler(w http.ResponseWriter, r *http.Request) {
	fmt.Fprintln(w, "Request address:", r.URL.Path)
	fmt.Fprintln(w, "URL Parameters:", r.URL.RawQuery)
	fmt.Fprintln(w, "Request header information", r.Header)
	fmt.Fprintln(w, "Request header Accept-Encoding Information", r.Header["Accept-Encoding"])

	//body := make([]byte, r.ContentLength)
	//r.Body.Read(body)
	//fmt.Fprintln(w, "body parameter:", string(body))

	// Obtain parameters through encapsulated methods
	r.ParseForm()
	// Get parameters on body+URL
	fmt.Fprintln(w, "body Parameters:", r.Form)
	// Only get the parameters in the body
	fmt.Fprintln(w, "post body Parameters:", r.PostForm)
	// If it is a file upload request; Using r.MultipartForm

	// Get the parameters directly through the key without calling the r.ParseForm() function
	fmt.Fprintln(w, "parameter name: ", r.FormValue("name"))
	fmt.Fprintln(w, "parameter name: ", r.PostFormValue("name"))
	
}

Static resource processing

func htmlHandler(w http.ResponseWriter, r *http.Request) {
	t := template.Must(template.ParseFiles("html/index.html"))
	t.Execute(w, "welcome")
}

// Static resource processing
func main()  {

	// Static resource (css, js, or static html) processing: if the access path starts with / static /, use file service processing, and the root path of the file is 	 static;
	http.Handle("/static/",
		http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
	// Handle html rendering
	http.HandleFunc("/html", htmlHandler)
	http.ListenAndServe(":8081", nil)
}

13, Redis

Download redis module package

https://github.com/gomodule/redigo

# Execute the following command in the working directory of go
go get github.com/gomodule/redigo/redis

Common connection example

// Connect to redis
con, err := redis.Dial("tcp", "127.0.0.1:6379")
if err != nil {
    fmt.Println("redis Connection exception:", err)
    return
}
defer con.Close()

// Set value to redis
_, err = con.Do("Set", "name", "tom cat")
if err != nil {
    fmt.Println("error: ", err)
}
// Get value
val, err := redis.String(con.Do("Get", "name"))
if err != nil {
    fmt.Println("error: ", err)
    return
}
fmt.Println("", val)

// Operation hash
con.Do("HSet", "1", "name", "tom cat")
val, err = redis.String(con.Do("HGet", "1", "name"))
if err != nil {
    fmt.Println("error: ", err)
    return
}
fmt.Println("", val)

redis connection pool example

var redisPool *redis.Pool
func init() {
	redisPool = &redis.Pool{
		MaxIdle:     8,   // Maximum number of free connections
		MaxActive:   0,   // Indicates the maximum number of connections to the database. 0 indicates no limit
		IdleTimeout: 100, // Maximum idle time
		Dial: func() (redis.Conn, error) { // Create redis connection
			return redis.Dial("tcp", "127.0.0.1:6379")
		},
	}
}

func main() {
	conn := redisPool.Get()
	defer conn.Close()
	defer redisPool.Close()

	_, err := conn.Do("Set", "name", "Tom Cat")
	if err != nil {
		fmt.Println("Setting exception:", err)
		return
	}
	val, err := redis.String(conn.Do("Get", "name"))
	fmt.Println(val)
}

14, MySQL

Download driver package

# Source address
https://github.com/go-sql-driver/mysql

# Download driver package
go get github.com/go-sql-driver/mysql

configure connections

// Create connection
func MysqlInit(){
	Db, dbErr = sql.Open("mysql", "root:123456@tcp(127.0.0.1:3306)/demo_go")
	if dbErr != nil {
		panic(dbErr.Error())
	}
}

Add data

// Add data
func (m *Member) AddMember() error {

    sql := "insert into member(`name`, password, email) values(?, ?, ?)"
    // Precompiled SQL
    inSmt, err := Db.Prepare(sql)
    if err != nil {
        fmt.Println("SQL Statement precompiling exception", err)
        return err
    }
    
    // implement
    _, err = inSmt.Exec(m.Name, m.Password, m.Email)
    if err != nil {
        fmt.Println("SQL Execution exception", err)
        return err
    }
    return nil
}

Query a piece of data

func findById(id int) (m *Member, err error)  {

	sql := "select * from member where id=?"
	// Query a piece of data
	row := Db.QueryRow(sql, id)

	var name, password, email string
	err = row.Scan(&id, &name, &password, &email)
	if err != nil{
		fmt.Println(err.Error())
		return
	}
	m = &Member{Id: id, Name: name, Password: password, Email: email}
	return
}

Query multiple data

func findAll() (ms []Member, err error)  {

    sql := "select * from member"
    // Query a piece of data
    rows, err := Db.Query(sql)
    if err != nil{
    fmt.Println(err.Error())
        return
    }

    for rows.Next() {
        var id int
        var name, password, email string
        err = rows.Scan(&id, &name, &password, &email)
        if err != nil{
            fmt.Println(err.Error())
            return
        }
        m := Member{Id: id, Name: name, Password: password, Email: email}
        ms = append(ms, m)
    }
    return
}

Follow the wechat subscription number "landing star" to get the latest information

Keywords: Go

Added by laknal on Tue, 08 Mar 2022 12:56:01 +0200