Golang basic learning notes, quickly understand the basic grammar of golang.
Learning materials
- Super complete golang interview questions collection + golang Learning Guide + golang knowledge map + entry growth route ; One covers the core knowledge that most golang programmers need to master
- Han Shunping's golang video tutorial , the video is on station B. It's best to play it at double speed.
- go locale configuration
- Go package website golang.com.cn is the Chinese version of Go package website. golang.org is the main site of Go open source project, while golang com. Cn provides rich resources and documents for Go users, which is an important part of Go ecology.
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