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.
G
It is a goroutine, which contains information about the goroutine and its binding to the P.P
Manages 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:
- Sending values to a closed channel can cause panic.
- Receiving on a closed channel fetches values until the channel is empty.
- A receive operation on a closed channel with no value results in a zero value of the corresponding type.
- 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<- int
Is a write-only one-way channel (only int can be written to it) that can be sent but cannot be received.<-chan int
Is 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?
-
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.
-
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”