[www.liwenzhou.com/][https://w…]

Golang 中文文档 address: studygolang.com/pkgdoc Go language basic syntax (1)

1. The operator

Operators built into the Go language are:

  1. Arithmetic operator
  2. Relational operator
  3. Logical operator
  4. An operator
  5. The assignment operator

Arithmetic operator

The operator describe
+ add
Subtracting the
* multiply
/ division
% For more than

Note: ++ (increment) and — (decrement) are separate statements in Go, not operators.

Relational operator

The operator describe
= = Checks if two values are equal, returning True if they are, False otherwise.
! = Checks if two values are not equal, returning True if not False otherwise.
> Checks if the value on the left is greater than the value on the right, and returns True if so, False otherwise.
> = Checks if the value on the left is greater than or equal to the value on the right, and returns True if so, False otherwise.
< Checks if the value on the left is less than the value on the right, and returns True if so, False otherwise.
< = Checks if the value on the left is less than or equal to the value on the right, and returns True if it is False otherwise.

Logical operator

The operator describe
&& The logical AND operator. True if both operands are True, False otherwise.
|| The logical OR operator. True if the operands on both sides have a True, False otherwise.
! Logical NOT operator. False if the condition is True, True otherwise.

An operator

Bitwise operators operate on the binary bits of integers in memory.

The operator describe
& The binary phase of each of the two numbers involved in the operation. (1 only if both of them are 1)
| The binary phase or of each of the two numbers involved in the operation. (If one of them is 1, it’s 1.)
^ The result is 1 when the corresponding binary digits of the two numbers involved in the operation are different or when the corresponding binary digits are different. (1 if the two digits are different)
<< To the left n is 2 to the n. “A <<b” is to move all the binary bits of A to the left by B bits, discard the high bits and fill the low ones with 0 bits.
>> If you move to the right n places, you divide by 2 to the n. “A >> B” is to shift all the binaries of A to the right by B bits.

The assignment operator

The operator describe
= A simple assignment operator that assigns the value of an expression to an lvalue
+ = Add them and assign them
– = Subtract and assign
* = Multiply and assign
/ = Divide and assign
% = Remainder and then assign
< < = Assign after left shift
> > = Assign after right shift
& = Assignment by bit and post
| = Assignment by bit or post
^ = Xor post assignment by bit

An array of 2.

An array is a collection of elements of the same data type. In Go, arrays are defined from the time they are declared, and the array members can be changed as you use them, but the array size cannot be changed. Basic syntax:

// Define an array a of length 3 and type int
var a [3]int
Copy the code
2.1 Array Definition:
Var Array variable name [element number]TCopy the code

For example, var a [5]int, the length of the array must be constant, and the length must be part of the array type. Once defined, the length cannot change. [5]int and [10]int are different types.

var a [3]int
var b [4]int
a = b // Do not do this because a and B are of different types
Copy the code

Array can be accessed by subscript, the subscript is 0, the last element subscript is: len-1, access out of bounds (index is outside the legal range), triggering access out of bounds, panic.

2.2 Array initialization:

Arrays can also be initialized in a number of ways.

Methods a

When initializing an array, you can use the initializer list to set the values of the array elements.

func main(a) {
	var testArray [3]int                        // The array is initialized to a zero value of type int
	var numArray = [3]int{1.2}                 // Complete the initialization with the specified initial value
	var cityArray = [3]string{"Beijing"."Shanghai"."Shenzhen"} // Complete the initialization with the specified initial value
	fmt.Println(testArray)                      / / [0 0 0]
	fmt.Println(numArray)                       / / [1, 2 0]
	fmt.Println(cityArray)                      //[Beijing, Shanghai and Shenzhen]
}
Copy the code

Method 2

Make sure the initial value is the same as the length of the array. In general, we can let the compiler infer the length of the array based on the number of initial values. For example:

func main(a) {
	var testArray [3]int
	var numArray = [...]int{1.2}
	var cityArray = [...]string{"Beijing"."Shanghai"."Shenzhen"}
	fmt.Println(testArray)                          / / [0 0 0]
	fmt.Println(numArray)                           / / [1, 2]
	fmt.Printf("type of numArray:%T\n", numArray)   //type of numArray:[2]int
	fmt.Println(cityArray)                          //[Beijing, Shanghai and Shenzhen]
	fmt.Printf("type of cityArray:%T\n", cityArray) //type of cityArray:[3]string
}
Copy the code

Methods three

We can also initialize an array by specifying an index value, for example:

func main(a) {
	a := [...]int{1: 1.3: 5}
	fmt.Println(a)                  // [0 1 0 5]
	fmt.Printf("type of a:%T\n", a) //type of a:[4]int
}
Copy the code

2.3 Array traversal:

There are two ways to traverse group A:

func main(a) {
	var a = [...]string{"Beijing"."Shanghai"."Shenzhen"}
	// Method 1: for loop through
	for i := 0; i < len(a); i++ {
		fmt.Println(a[i])
	}

	// method 2: for range
	for index, value := range a {
		fmt.Println(index, value)
	}
}
Copy the code

3. Multidimensional arrays

The Go language supports multi-dimensional arrays, so let’s take two-dimensional arrays as an example (arrays nested within arrays).

3.1 Definition of two-dimensional array:

func main(a) {
	a := [3] [2]string{{"Beijing"."Shanghai"},
		{"Guangzhou"."Shenzhen"},
		{"Chengdu"."Chongqing"},
	}
	fmt.Println(a) //[[Beijing Shanghai] [Guangzhou Shenzhen] [Chengdu Chongqing]]
	fmt.Println(a[2] [1]) // Index Value: Chongqing
}
Copy the code

3.2 Traversal of two-dimensional arrays:

func main(a) {
	a := [3] [2]string{{"Beijing"."Shanghai"},
		{"Guangzhou"."Shenzhen"},
		{"Chengdu"."Chongqing"}},for _, v1 := range a {
		for _, v2 := range v1 {
			fmt.Printf("%s\t", v2)
		}
		fmt.Println()
	}
}
Copy the code

Output:

Beijing Shanghai Guangzhou Shenzhen Chengdu ChongqingCopy the code

Note: Only the first layer of a multidimensional array can be used… To let the compiler derive the array length. Such as:

// The supported writing methoda := [...] [2]string{{"Beijing"."Shanghai"},
	{"Guangzhou"."Shenzhen"},
	{"Chengdu"."Chongqing"}},// The inner layer of multidimensional arrays is not supported...
b := [3] [...].string{{"Beijing"."Shanghai"},
	{"Guangzhou"."Shenzhen"},
	{"Chengdu"."Chongqing"}},Copy the code

3.4 Arrays are value types

Arrays are value types. Assignments and passes copy the entire array. So changing the value of the copy does not change the value of the copy itself.

func modifyArray(x [3]int) {
	x[0] = 100
}

func modifyArray2(x [3][2]int) {
	x[2] [0] = 100
}
func main(a) {
	a := [3]int{10.20.30}
	modifyArray(a) // Modify is a copy of A x
	fmt.Println(a) / / 20 30 [10]
	b := [3] [2]int{{1.1},
		{1.1},
		{1.1},
	}
	modifyArray2(b) // Modify is a copy of B x
	fmt.Println(b)  //[[1 1] [1 1]]
}
Copy the code

Note:

  1. Arrays support “==”, “! = “operator, because memory is always initialized.
  2. [n]*TRepresents an array of Pointers,*[n]TRepresents an array pointer.

Complete code:

package main

import "fmt"

func main(a) {
	// Array definition
	var a1 [3]bool
	fmt.Println(a1) // [false false false]
	var a2 [4]bool
	fmt.Printf("a1:%T a2:%T\n", a1, a2)

	// Array initialization
	a1 = [3]bool{true.true.false}1 / / way
	fmt.Println(a1)
	a3 := [...]int{1.2.3.4.5.6.7.8.9}2 / / way
	fmt.Println(a3)
	a4 := [5]int{1.2}3 / / way
	fmt.Println(a4)// [1 2 0 0 0]
	a5 := [5]int{0:1.4:2}4 / / way
	fmt.Println(a5)// [1 0 0 0 2]

	// Array traversal
	citys := [...]string{"Beijing"."Shanghai"."Shenzhen"}
	// 1. Traversal by index
	for i:=0; i<len(citys); i++ { fmt.Println(citys[i]) }// 2
	for index,value := range citys{
		fmt.Println(index,value)
	}

	// Multi-dimensional array
	var arr [3] [2]int
	arr = [3] [2]int{[2]int{1.2},2]int{3.4},2]int{5.6},
	}
	fmt.Println(arr)

	// Multi-dimensional array traversal
	for _,value := range arr{
		for _,v := range value{
			fmt.Println(v)
		}
	}

	// Arrays are value types
	b1 := [3]int{1.2.3}
	b2 := b1
	b2[0] = 100
	fmt.Println(b1,b2)// [1 2 3] [100 2 3]
}
Copy the code

4. Slice

4.1 the introduction

Because the length of an array is fixed and is part of a type, arrays have many limitations. Such as:

func arraySum(x [3]int) int{
    sum := 0
    for _, v := range x{
        sum = sum + v
    }
    return sum
}
Copy the code

This summation function accepts only [3] ints, and nothing else. For example,

a := [3]int{1.2.3}
Copy the code

We already have three elements in array A, so we can’t add any more elements to array A.

4.1 Definition of slice

A Slice is a variable-length sequence of elements of the same type. It is a layer of encapsulation based on the array type. It is very flexible and supports automatic expansion.

A slice is a reference type whose internal structure contains an address, length, and capacity. Slicing is generally used to quickly manipulate a collection of data.

4.2 Slice declaration syntax

The basic syntax for declaring slice types is as follows:

var name []T
Copy the code

Among them:

  • name: indicates the variable name
  • T: indicates the element type in the slice

Here’s an example:

func main(a) {
	// Declare the slice type
	var a []string              // Declare a string slice
	var b = []int{}             // Declare an integer slice and initialize it
	var c = []bool{false.true} // Declare a Boolean slice and initialize it
	var d = []bool{false.true} // Declare a Boolean slice and initialize it
	fmt.Println(a)              / / []
	fmt.Println(b)              / / []
	fmt.Println(c)              //[false true]
	fmt.Println(a == nil)       //true
	fmt.Println(b == nil)       //false
	fmt.Println(c == nil)       //false
	// FMT.Println(c == d) // Slice is a reference type and can only be compared to nil
}
Copy the code

4.3 Section length and capacity

Slices have their own length and capacity. We can calculate the length of slices by using the built-in len() function and the capacity of slices by using the built-in cap() function.

4.4 Slice expression

A slice expression constructs a substring or slice from a string, array, or pointer to an array or slice. It comes in two variants: a simple form that specifies low and high index bounds, and a full form that specifies capacity in addition to low and high index bounds.

Simple slice expression

The bottom layer of a slice is an array, so we can get a slice based on an array through a slice expression. Low and high in the slice expression represent an index range (left included, right excluded), that is, in the following code, elements 1<= index value <4 from array A are selected to form slice S, the length of the slice obtained is =high-low, and the capacity is equal to the capacity of the underlying array of the slice obtained.

func main(a) {
	a := [5]int{1.2.3.4.5}
	s := a[1:3]  // s := a[low:high]
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
}
Copy the code

Output:

s:[2 3] len(s):2 cap(s):4
Copy the code

For convenience, you can omit any indexes in the slice expression. Omitting low defaults to 0; Omitting high defaults to the length of the slice operand:

a[2:]  // same as a[2:len(a)]
a[:3]  // equivalent to a[0:3]
a[:]   // same as a[0:len(a)]
Copy the code

Note:

For arrays or strings, the index is valid if 0 <= low <= high <= len(a), otherwise the index is out of range.

When the slice expression is executed for the slice again (slice again slice), the upper bound of high is the capacity cap(a) of the slice, not the length. A constant index must be non-negative and can be represented by a value of type int; For arrays or constant strings, the constant index must also be in a valid range. If both low and high are constants, they must satisfy low <= high. A runtime panic occurs if the index is out of range at run time.

func main(a) {
	a := [5]int{1.2.3.4.5}
	s := a[1:3]  // s := a[low:high]
	fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
	s2 := s[3:4]  // Index cap(s) instead of len(s)
	fmt.Printf("s2:%v len(s2):%v cap(s2):%v\n", s2, len(s2), cap(s2))
}
Copy the code

Output:

s:[2 3] len(s):2 cap(s):4
s2:[5] len(s2):1 cap(s2):1
Copy the code

Complete slice expression

For arrays, Pointers to arrays, or slice a(not strings) support full slice expressions:

a[low : high : max]
Copy the code

The above code constructs a slice of the same type, length, and elements as the simple slice expression A [low: high]. In addition, it sets the capacity of the resulting slice to max-low. Only the first index value (low) can be omitted in the full slice expression; It defaults to 0.

func main(a) {
	a := [5]int{1.2.3.4.5}
	t := a[1:3:5]
	fmt.Printf("t:%v len(t):%v cap(t):%v\n", t, len(t), cap(t))
}
Copy the code

Output result:

t:[2 3] len(t):2 cap(t):4
Copy the code

The conditions for a complete slice expression are 0 <= low <= high <= Max <= cap(a), and other conditions are the same as those for a simple slice expression.

4.5 Use the make() function to construct slices

If you want to create a slice dynamically, you need to use the built-in make() function, which has the following format:

make([]T, size, cap)
Copy the code

Among them:

  • T: The element type of the slice
  • size: The number of elements in the slice
  • cap: Slice capacity

Here’s an example:

func main(a) {
	a := make([]int.2.10)
	fmt.Println(a)      / / [0, 0]
	fmt.Println(len(a)) / / 2
	fmt.Println(cap(a)) / / 10
}
Copy the code

In the code above, 10 internal storage Spaces of A have been allocated, but only 2 are actually used. Capacity does not affect the number of current elements, so len(a) returns 2 and cap(a) returns the capacity of the slice.

4.6 Nature of slicing

The essence of slicing is to encapsulate the underlying array. It contains three pieces of information: the pointer to the underlying array, the length of the slice (Len) and the capacity of the slice (CAP).

For example, we now have an array a := [8]int{0, 1, 2, 3, 4, 5, 6, 7}, sliced s1 := a[:5], as shown in the following diagram.

Section S2 := a[3:6], corresponding schematic diagram is as follows:

4.7 Determine whether the slice is empty

To check if the slice is empty, always use len(s) == 0 and should not use s == nil.

4.8 Sections cannot be directly compared

Slices cannot be compared, and we cannot use the == operator to determine whether two slices contain all equal elements. The only valid comparison operation for slicing is to compare to nil. A nil slice has no underlying array. A nil slice has a length and a capacity of 0. But we can’t say that a slice with both length and capacity 0 is nil, as in the following example:

var s1 []int         //len(s1)=0; cap(s1)=0; s1==nil
s2 := []int{}        //len(s2)=0; cap(s2)=0; s2! =nil
s3 := make([]int.0) //len(s3)=0; cap(s3)=0; s3! =nil
Copy the code

Therefore, to determine whether a slice is empty, len(s) == 0 should not be used to determine s == nil.

4.9 Assigned copy of slices

The following code demonstrates that both variables share the underlying array before and after the copy. It is important to note that changes to one slice affect the contents of the other.

func main(a) {
	s1 := make([]int.3) / / [0 0 0]
	s2 := s1             // Assign s1 directly to s2. S1 and S2 share the same underlying array
	s2[0] = 100
	fmt.Println(s1) / / [100 0 0]
	fmt.Println(s2) / / [100 0 0]
}
Copy the code

4.10 Slice traversal

Slice traversal is the same as array traversal, supporting index traversal and for range traversal.

func main(a) {
	s := []int{1.3.5}

	for i := 0; i < len(s); i++ {
		fmt.Println(i, s[i])
	}

	for index, value := range s {
		fmt.Println(index, value)
	}
}
Copy the code

4.11 Append () method adds elements to slice

The Go language’s built-in function Append () can dynamically add elements to slices. You can add one element at a time, you can add multiple elements, or you can add elements from another slice (followed by…). .

func main(a){
	var s []int
	s = append(s, 1)        / / [1]
	s = append(s, 2.3.4)  // [1 2 3 4]
	s2 := []int{5.6.7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]
}
Copy the code

** Note: the null slice declared by var can be used directly in the append() function without initialization.

var s []int
s = append(s, 1.2.3)
Copy the code

There is no need to initialize a slice and pass it into the append() function as shown below,

s := []int{}  // No initialization is necessary
s = append(s, 1.2.3)

var s = make([]int)  // No initialization is necessary
s = append(s, 1.2.3)
Copy the code

Each slice points to an underlying array, and when the array is large enough, new elements are added. When the underlying array cannot contain new elements, the slice will be automatically expanded according to certain policies, and the underlying array pointed to by the slice will be replaced. The “expansion” operation usually occurs when the append() function is called, so we usually need to receive the return value of the Append function in the original variable.

Here’s an example:

func main(a) {
	//append() adds elements and slices for expansion
	var numSlice []int
	for i := 0; i < 10; i++ {
		numSlice = append(numSlice, i)
		fmt.Printf("%v len:%d cap:%d ptr:%p\n", numSlice, len(numSlice), cap(numSlice), numSlice)
	}
}
Copy the code

Output:

[0]  len:1  cap:1  ptr:0xc0000a8000
[0 1]  len:2  cap:2  ptr:0xc0000a8040
[0 1 2]  len:3  cap:4  ptr:0xc0000b2020
[0 1 2 3]  len:4  cap:4  ptr:0xc0000b2020
[0 1 2 3 4]  len:5  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5]  len:6  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6]  len:7  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7]  len:8  cap:8  ptr:0xc0000b6000
[0 1 2 3 4 5 6 7 8]  len:9  cap:16  ptr:0xc0000b8000
[0 1 2 3 4 5 6 7 8 9]  len:10  cap:16  ptr:0xc0000b8000
Copy the code

As can be seen from the above results:

  1. append()The function appends the element to the end of the slice and returns the slice.
  2. The capacity of numSlice is automatically expanded according to the rule 1,2,4,8,16. After each expansion, the capacity is doubled.

The append() function also supports appending multiple elements at once. Such as:

var citySlice []string
// Appends an element
citySlice = append(citySlice, "Beijing")
// Append multiple elements
citySlice = append(citySlice, "Shanghai"."Guangzhou"."Shenzhen")
// Append slices
a := []string{"Chengdu"."Chongqing"}
citySlice = append(citySlice, a...)
fmt.Println(citySlice) //[Beijing Shanghai Guangzhou Shenzhen Chengdu Chongqing]
Copy the code

4.12 The copy() function copies slices

Let’s start with a question:

func main(a) {
	a := []int{1.2.3.4.5}
	b := a
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(b) //[1 2 3 4 5]
	b[0] = 1000
	fmt.Println(a) //[1000 2 3 4 5]
	fmt.Println(b) //[1000 2 3 4 5]
}
Copy the code

Since slices are references, both A and B actually refer to the same memory address. When you change B, you change the value of A.

Go’s built-in copy() function can quickly copy data from one slice to another. The format of copy() function is as follows:

copy(destSlice, srcSlice []T)
Copy the code

Among them:

  • SrcSlice: indicates the slice of data source
  • DestSlice: indicates the destination slice

Here’s an example:

func main(a) {
	// copy() copies slices
	a := []int{1.2.3.4.5}
	c := make([]int.5.5)
	copy(c, a)     // Use copy() to copy the elements in slice A to slice C
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}
Copy the code

4.13 Deleting elements from a slice

There is no special way to delete slice elements in Go, we can use the features of slice itself to delete elements. The code is as follows:

func main(a) {
	// Remove the element from the slice
	a := []int{30.31.32.33.34.35.36.37}
	// Delete the element with index 2
	a = append(a[:2], a[3:]...). fmt.Println(a)//[30 31 33 34 35 36 37]
}
Copy the code

A = append(a[:index], a[index+1:]…)

Pointer to 5.

Different from the pointer in C/C++, the pointer in Go language cannot be offset and operation, is a safe pointer.

To understand Pointers in Go, you need to know three concepts: pointer address, pointer type, and pointer value.

5.1 Pointers in Go

Any program data loaded into memory has its address in memory, which is called a pointer. In order to store an address in memory, we need pointer variables.

For example, “Never overestimate yourself” is my motto, AND I want to write it into the program. As soon as the program starts, this sentence is loaded into memory (assuming memory address 0x123456), and I assign this statement to variable A and memory address to variable B in the program. The variable B is a pointer variable. My motto can be found in both variable A and variable B.

Pointers in Go cannot be offset and computed, so pointer manipulation in Go is very simple and we only need to remember two symbols:

  • &Address:
  • *: The value is based on the address

5.2 Pointer Address and Pointer type

Each variable has an address at run time that represents its location in memory. The Go language uses the & character in front of a variable to “fetch the address”. Value types (int, float, bool, string, array, struct) in Go have corresponding pointer types, such as: *int, *int64, *string, etc.

The syntax for fetching a variable pointer is as follows:

ptr := &v    // v is of type T
Copy the code

Among them:

  • v: Represents the variable to be fetched, of typeT
  • ptr: the variable used to receive the address. PTR is of type*T, called a pointer type to T. * stands for pointer.

Here’s an example:

func main(a) {
	a := 10
	b := &a
	fmt.Printf("a:%d ptr:%p\n", a, &a) // a:10 ptr:0xc00001a078
	fmt.Printf("b:%p type:%T\n", b, b) // b:0xc00001a078 type:*int
	fmt.Println(&b)                    // 0xc00000e018
}
Copy the code

Let’s take a look at the diagram of b := &a:

5.3 Pointer Values

A pointer to an ordinary variable can be obtained by using the & operator to fetch the address. A pointer can then be operated on with *, the value of the pointer, as follows.

func main(a) {
	// Pointer value
	a := 10
	b := &a // take the address of variable A and save the pointer to b
	fmt.Printf("type of b:%T\n", b)
	c := *b // Pointer value (based on the pointer to memory)
	fmt.Printf("type of c:%T\n", c)
	fmt.Printf("value of c:%v\n", c)
}
Copy the code

The output is as follows:

type of b:*int
type of c:int
value of c:10
Copy the code

Conclusion: the address-fetch operator & and the value operator * are complementary operators. The & retrieves the address, and * retrieves the value pointed to by the address.

The interrelations and characteristics of variable, pointer address, pointer variable, address fetch, and value are as follows:

  • Fetch the address of a variable (&) to get a pointer to the variable.
  • The value of a pointer variable is a pointer address.
  • Value a pointer variable (*) to obtain the value of the original variable to which the pointer variable points.

Example of pointer value transfer:

func modify1(x int) {
	x = 100
}

func modify2(x *int) {
	*x = 100
}

func main(a) {
	a := 10
	modify1(a)
	fmt.Println(a) / / 10
	modify2(&a)
	fmt.Println(a) / / 100
}
Copy the code

5.4 the new and the make

Let’s start with an example:

func main(a) {
	var a *int
	*a = 100
	fmt.Println(*a)

	var b map[string]int
	b[shahenaza] = 100
	fmt.Println(b)
}
Copy the code

Executing the above code causes panic. Why? In Go, when we use a variable of reference type, we not only declare it, but also allocate memory space for it, otherwise our value cannot be stored. Declarations of value types do not allocate memory because they are already allocated memory by default when they are declared. To allocate memory, we have today’s new and make. New and make are two built-in functions in Go that allocate memory.

new

New is a built-in function with the following function signature:

func new(Type) *Type
Copy the code

Among them,

  • Type stands for Type, and the new function takes only one argument, which is a Type
  • The new function returns a pointer to the memory address of the Type.

The new function is not very common. You get a pointer to a type that has a zero value for that type. Here’s an example:

func main(a) {
	a := new(int)
	b := new(bool)
	fmt.Printf("%T\n", a) // *int
	fmt.Printf("%T\n", b) // *bool
	fmt.Println(*a)       / / 0
	fmt.Println(*b)       // false
}	
Copy the code

In the example code at the beginning of this section, var a *int only declares a pointer variable a but does not initialize it. The pointer, as a reference type, needs to be initialized before it has the memory to assign a value to it. We should initialize a using the built-in new function as follows:

func main(a) {
	var a *int
	a = new(int)
	*a = 10
	fmt.Println(*a)
}
Copy the code
make

Make is also used to allocate memory. Unlike new, it is only used to create memory for slice, map, and chan, and it returns the three types themselves, not their pointer types. Since these three types are reference types, there is no need to return their Pointers. The make function has the following function signature:

func make(t Type, size ... IntegerType) Type
Copy the code

There is no substitute for make. Slice, Map, and channel all need to be initialized with make before they can be manipulated. We explained this in the previous chapter, and we will elaborate on channel in the following chapters.

Var b map[string]int specifies that b is a map variable, and that it needs to be initialized using the make function as in the following example:

func main(a) {
	var b map[string]int
	b = make(map[string]int.10)
	b[shahenaza] = 100
	fmt.Println(b)
}
Copy the code
The difference between new and make
  1. Both are used for memory allocation.
  2. Make is only used to initialize slice, map, and channel, and returns the three reference types themselves.
  3. New is used for the memory allocation of the type, and the corresponding value of the memory is type zero, and returns a pointer to the type.

6. Map

The mapping container provided by Go language is Map, which uses hash internally.

6.1 the map is introduced

A map is an unordered key-value based data structure. In Go, a map is a reference type and must be initialized before it can be used.

6.2 the map definition

The map definition syntax in Go language is as follows:

map[KeyType]ValueType
Copy the code

Among them,

  • KeyType: indicates the KeyType.
  • ValueType: indicates the ValueType of the key.

Map variables default to nil and use the make() function to allocate memory. Grammar:

make(map[KeyType]ValueType, [cap])
Copy the code

Cap represents the capacity of the map. This parameter is not required, but an appropriate capacity should be specified when the map is initialized.

6.3 Basic Use of Map

The data in map comes in pairs. The basic code for using map is as follows:

func main(a) {
	scoreMap := make(map[string]int.8)
	scoreMap["Zhang"] = 90
	scoreMap["Xiao Ming"] = 100
	fmt.Println(scoreMap)
	fmt.Println(scoreMap["Xiao Ming"])
	fmt.Printf("type of a:%T\n", scoreMap)
}
Copy the code

Output:

[Xiaoming :100 zhangs3:90] 100type of a:map[string]int
Copy the code

Map also supports padding elements at declaration time, for example:

func main(a) {
	userInfo := map[string]string{
		"username": "The Little Prince of Sand River"."password": "123456",
	}
	fmt.Println(userInfo) // map[password:123456 username: 123456]
}
Copy the code

6.4 Checking whether a Key Exists

In Go, there is a special way to determine whether a key exists in a map. The format is as follows:

value, ok := map[key]
Copy the code

Here’s an example:

func main(a) {
	scoreMap := make(map[string]int)
	scoreMap["Zhang"] = 90
	scoreMap["Xiao Ming"] = 100
	// if key exists, ok is true and v is the corresponding value; There is no zero value where OK is false and v is a value type
	v, ok := scoreMap["Zhang"]
	if ok {
		fmt.Println(v)
	} else {
		fmt.Println("No trace of him.")}}Copy the code

6.5 Map Traversal

Go uses for range to traverse a map.

func main(a) {
	scoreMap := make(map[string]int)
	scoreMap["Zhang"] = 90
	scoreMap["Xiao Ming"] = 100
	scoreMap["娜扎"] = 60
	for k, v := range scoreMap {
		fmt.Println(k, v)
	}
}
Copy the code

But if we just want to iterate over the key, we can write it like this:

func main(a) {
	scoreMap := make(map[string]int)
	scoreMap["Zhang"] = 90
	scoreMap["Xiao Ming"] = 100
	scoreMap["娜扎"] = 60
	for k := range scoreMap {
		fmt.Println(k)
	}
}
Copy the code

Note: The order in which the elements are iterated through the map is independent of the order in which the key-value pairs are added.

6.6 The delete() function Deletes key-value pairs

Delete a set of key-value pairs from a map using the delete() built-in function, which has the following format:

delete(map, key)
Copy the code

Among them:

  • Map: indicates the map of the key-value pair to be deleted
  • Key: indicates the key of the key-value pair to be deleted

Example code is as follows:

func main(a){
	scoreMap := make(map[string]int)
	scoreMap["Zhang"] = 90
	scoreMap["Xiao Ming"] = 100
	scoreMap["娜扎"] = 60
	delete(scoreMap, "Xiao Ming")// Delete xiaoming :100 from map
	for k,v := range scoreMap{
		fmt.Println(k, v)
	}
}
Copy the code

6.7 Traversing the Map in the Specified Sequence

func main(a) {
	rand.Seed(time.Now().UnixNano()) // Initializes the random number seed

	var scoreMap = make(map[string]int.200)

	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("stu%02d", i) // Generate a string beginning with stu
		value := rand.Intn(100)          // Generate random integers from 0 to 99
		scoreMap[key] = value
	}
	// Remove all keys from map and store them in slice keys
	var keys = make([]string.0.200)
	for key := range scoreMap {
		keys = append(keys, key)
	}
	// Sort the slices
	sort.Strings(keys)
	// Traverses the map according to the sorted key
	for _, key := range keys {
		fmt.Println(key, scoreMap[key])
	}
}
Copy the code

6.8 Elements are Slices of map type

The following code shows what happens when elements in a slice are of type map:

func main(a) {
	var mapSlice = make([]map[string]string.3)
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
	fmt.Println("after init")
	// Initialize the map element in the slice
	mapSlice[0] = make(map[string]string.10)
	mapSlice[0] ["name"] = "The Little Prince"
	mapSlice[0] ["password"] = "123456"
	mapSlice[0] ["address"] = "Sha"
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
}
Copy the code

6.9 The value is a slice map

The following code demonstrates an operation with a value of slice type in a map:

func main(a) {
	var sliceMap = make(map[string] []string.3)
	fmt.Println(sliceMap)
	fmt.Println("after init")
	key := "China"
	value, ok := sliceMap[key]
	if! ok { value =make([]string.0.2)
	}
	value = append(value, "Beijing"."Shanghai")
	sliceMap[key] = value
	fmt.Println(sliceMap)
}
Copy the code

Function of 7.

Go supports functions, anonymous functions, and closures, and functions are “first-class citizens” in Go.

7.1 Function Definition

Func keyword is used to define functions in Go language, and the specific format is as follows:

funcThe function name(parameters)(Return value){function body}Copy the code

Among them:

  • Function name: Contains letters, digits, and underscores (_). But the first letter of the function name cannot be a number. Function names cannot be the same within the same package (see package concepts below).
  • Parameter: A parameter consists of a parameter variable and the type of the parameter variable. It is used between multiple parameters.Space.
  • Return value: A return value consists of a return value variable and its variable type. You can also write only the type of the return value. Multiple return values must be used(a)Wrap and use.Space.
  • Function body: a block of code that implements a specified function.

Let’s first define a function that adds two numbers:

func intSum(x int, y int) int {
	return x + y
}
Copy the code

Function arguments and return values are optional. For example, we can implement a function that takes neither arguments nor returns values:

func sayHello(a) {
	fmt.Println(Shahe, "Hello")}Copy the code

7.2 Function Invocation

Once the function is defined, we can call the function by its name (). For example, if we call the two functions defined above, the code looks like this:

func main(a) {
	sayHello()
	ret := intSum(10.20)
	fmt.Println(ret)
}
Copy the code

Note that you can call a function with a return value without receiving its return value.

7.3 parameter

7.3.1 Type shorthand

If adjacent variables in a function have the same type, the type can be omitted. For example:

func intSum(x, y int) int {
	return x + y
}
Copy the code

In the above code, the intSum function takes two arguments, both of type int, so we can omit the type of x, because y is typed, and x is the same type.

7.3.2 Variable Parameters

A variable parameter is a function that has an unfixed number of arguments. Variable arguments in the Go language are made by adding… To identify.

Note: A variable argument is usually the last argument to a function.

Here’s an example:

func intSum2(x ...int) int {
	fmt.Println(x) //x is a slice
	sum := 0
	for _, v := range x {
		sum = sum + v
	}
	return sum
}
Copy the code

Call the above function:

ret1 := intSum2()
ret2 := intSum2(10)
ret3 := intSum2(10.20)
ret4 := intSum2(10.20.30)
fmt.Println(ret1, ret2, ret3, ret4) / / 0 10 30 to 60
Copy the code

When a fixed parameter is used with a variable parameter, the variable parameter should be placed after the fixed parameter. The example code is as follows:

func intSum3(x int, y ...int) int {
	fmt.Println(x, y)
	sum := x
	for _, v := range y {
		sum = sum + v
	}
	return sum
}
Copy the code

Call the above function:

ret5 := intSum3(100)
ret6 := intSum3(100.10)
ret7 := intSum3(100.10.20)
ret8 := intSum3(100.10.20.30)
fmt.Println(ret5, ret6, ret7, ret8) / / 100 110 130 160
Copy the code

Essentially, the variable arguments of a function are implemented by slicing.

7.4 the return value

In Go, the return keyword is used to output the return value.

7.4.1 Multiple Return Values

The Go language supports multiple return values for functions. If a function has multiple return values, it must wrap all return values with ().

Here’s an example:

func calc(x, y int) (int.int) {
	sum := x + y
	sub := x - y
	return sum, sub
}
Copy the code
7.4.2 Return Value naming

A function can be defined by naming its return value, using these variables directly in the function body, and finally returning it with the return keyword.

Such as:

func calc(x, y int) (sum, sub int) {
	sum = x + y
	sub = x - y
	return
}
Copy the code
7.4.3 Return Value Supplement

When one of our functions returns a value of type slice, nil is considered a valid slice, there is no need to show that it returns a slice of length 0.

func someFunc(x string) []int {
	if x == "" {
		return nil // Return []int{}}... }Copy the code

7.5 Variable scope

7.5.1 Global Variables

A global variable is a variable defined outside of a function that is valid for the entire running life of a program. Global variables can be accessed in functions.

package main

import "fmt"

// Define the global variable num
var num int64 = 10

func testGlobalVar(a) {
	fmt.Printf("num=%d\n", num) The global variable num can be accessed in the function
}
func main(a) {
	testGlobalVar() //num=10
}
Copy the code
7.5.2 Local variables

Local variables are divided into two types: variables defined inside a function cannot be used outside the function. For example, in the following example, the variable x defined in testLocalVar cannot be used in the main function:

func testLocalVar(a) {
	// define a function local variable x that is valid only within the function
	var x int64 = 100
	fmt.Printf("x=%d\n", x)
}

func main(a) {
	testLocalVar()
	fmt.Println(x) // The variable x cannot be used at this time
}
Copy the code

If the local variable has the same name as the global variable, the local variable is preferentially accessed.

package main

import "fmt"

// Define the global variable num
var num int64 = 10

func testNum(a) {
	num := 100
	fmt.Printf("num=%d\n", num) // Local variables are preferred in functions
}
func main(a) {
	testNum() // num=100
}
Copy the code

Next, let’s look at block-defined variables. We usually use this method for if conditions, for loops, and switch statements.

func testLocalVar2(x, y int) {
	fmt.Println(x, y) // Function parameters are valid only in this function
	if x > 0 {
		z := 100 // The z variable applies only to the if block
		fmt.Println(z)
	}
	// fmt.println (z)// Variable z cannot be used here
}
Copy the code

The variables defined in the for loop are only valid in the for block:

func testLocalVar3(a) {
	for i := 0; i < 10; i++ {
		fmt.Println(i) // The variable I is valid only in the current for block
	}
	// fmt.println (I) // The variable I cannot be used here
}
Copy the code

7.6 Function Types and Variables

7.6.1 Defining function types

We can use the type keyword to define a function type in the following format:

type calculation func(int.int) int
Copy the code

The above statement defines a Calculation type, which is a function type that takes two parameters of type int and returns a value of type int.

Simply put, all functions that meet this condition are calculation functions, for example, add and sub below are Calculation functions.

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

func sub(x, y int) int {
	return x - y
}
Copy the code

Both Add and sub can be assigned to variables of type Calculation.

var c calculation
c = add
Copy the code
7.6.2 Function Type Variables

We can declare a variable of function type and assign a value to it:

func main(a) {
	var c calculation               // Declare a calculation variable c
	c = add                         // assign add to c
	fmt.Printf("type of c:%T\n", c) // type of c:main.calculation
	fmt.Println(c(1.2))            // Call c like add

	f := add                        // Assign function add to variable f1
	fmt.Printf("type of f:%T\n", f) // type of f:func(int, int) int
	fmt.Println(f(10.20))          // Call f like add
}
Copy the code

7.7 Higher-order functions

Higher-order functions are divided into functions as parameters and functions as return values.

7.7.1 Functions as Parameters

Functions can be arguments:

func add(x, y int) int {
	return x + y
}
func calc(x, y int, op func(int.int) int) int {
	return op(x, y)
}
func main(a) {
	ret2 := calc(10.20, add)
	fmt.Println(ret2) / / 30
}
Copy the code
7.7.2 Function as return value

Function can also be used as a return value:

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

7.8 Anonymous Functions and closures

7.8.1 Anonymous Functions

Functions can of course still be returned, but in Go you can no longer define functions inside functions as before, only anonymous functions. An anonymous function is a function that does not have a function name. An anonymous function is defined in the following format:

func(parameters)(Return value){function body}Copy the code

Anonymous functions cannot be called like normal functions because they do not have a function name, so anonymous functions need to be saved to a variable or executed immediately:

func main(a) {
	// Save the anonymous function to a variable
	add := func(x, y int) {
		fmt.Println(x + y)
	}
	add(10.20) // Call an anonymous function through a variable

	// Self-executing functions: Anonymous functions are executed directly after the addition () is defined
	func(x, y int) {
		fmt.Println(x + y)
	}(10.20)}Copy the code

Anonymous functions are mostly used to implement callbacks and closures.

7.8.2 closure

A closure is an entity composed of a function and its associated reference environment. In simple terms, closures = function + reference environment. Let’s start with an example:

func adder(a) func(int) int {
	var x int
	return func(y int) int {
		x += y
		return x
	}
}
func main(a) {
	var f = adder()
	fmt.Println(f(10)) / / 10
	fmt.Println(f(20)) / / 30
	fmt.Println(f(30)) / / 60

	f1 := adder()
	fmt.Println(f1(40)) / / 40
	fmt.Println(f1(50)) / / 90
}
Copy the code

The variable f is a closure when it is a function and refers to the x variable in its outer scope. The variable X also remains valid throughout the life of F. Closure Advanced Example 1:

func adder2(x int) func(int) int {
	return func(y int) int {
		x += y
		return x
	}
}
func main(a) {
	var f = adder2(10)
	fmt.Println(f(10)) / / 20
	fmt.Println(f(20)) / / 40
	fmt.Println(f(30)) / / 70

	f1 := adder2(20)
	fmt.Println(f1(40)) / / 60
	fmt.Println(f1(50)) / / 110
}
Copy the code

Closure Advanced Example 2:

func makeSuffixFunc(suffix string) func(string) string {
	return func(name string) string {
		if! strings.HasSuffix(name, suffix) {return name + suffix
		}
		return name
	}
}

func main(a) {
	jpgFunc := makeSuffixFunc(".jpg")
	txtFunc := makeSuffixFunc(".txt")
	fmt.Println(jpgFunc("test")) //test.jpg
	fmt.Println(txtFunc("test")) //test.txt
}
Copy the code

Closure Advanced Example 3:

func calc(base int) (func(int) int.func(int) int) {
	add := func(i int) int {
		base += i
		return base
	}

	sub := func(i int) int {
		base -= i
		return base
	}
	return add, sub
}

func main(a) {
	f1, f2 := calc(10)
	fmt.Println(f1(1), f2(2)) / / 11 September
	fmt.Println(f1(3), f2(4)) / / 12 August
	fmt.Println(f1(5), f2(6)) / / 13 July
}
Copy the code

Closures aren’t really that complicated, just keep in mind that closures = function + reference context.

7.9 the defer statement

The DEFER statement in the Go language delays the statements that follow it. When the function to which defer belongs is about to return, the deferred statements are executed in reverse order as defined by defer; that is, the statements that were deferred first are executed last, and those that were deferred last are executed first.

Here’s an example:

func main(a) {
	fmt.Println("start")
	defer fmt.Println(1)
	defer fmt.Println(2)
	defer fmt.Println(3)
	fmt.Println("end")}Copy the code

Output result:

start
end
3
2
1
Copy the code

Because of the deferred nature of the defer statement, the defer statement is very handy for handling resource release issues. For example, resource clearing, file closing, unlocking, and recording time.

7.9.1 Defer Execution timing

In the function of Go language, the return statement is not atomic operation at the bottom, it is divided into two steps: assigning value to return value and RET instruction. The defer statement executes after the return value assignment and before the RET directive executes. The details are shown in the figure below:

7.9.2 Defer classic case

Read the code below and write the final print.

func f1(a) int {
	x := 5
	defer func(a) {
		x++
	}()
	return x
}

func f2(a) (x int) {
	defer func(a) {
		x++
	}()
	return 5
}

func f3(a) (y int) {
	x := 5
	defer func(a) {
		x++
	}()
	return x
}
func f4(a) (x int) {
	defer func(x int) {
		x++
	}(x)
	return 5
}
func main(a) {
	fmt.Println(f1())
	fmt.Println(f2())
	fmt.Println(f3())
	fmt.Println(f4())
}
Copy the code

7.10 Introduction to built-in Functions

Built-in function introduce
close It is used to close channels
len For lengths such as string, array, slice, map, channel
new Used to allocate memory, mainly used to allocate value types, such as int, struct. It returns a pointer
make Used to allocate memory, mainly used to allocate reference types, such as chan, map, slice
append Used to append elements to arrays and slices
Panic and recover It’s used for error handling
7.10.1 panic/recover

The Go language currently (Go1.12) has no exception mechanism, but uses panic/ Recover mode to handle errors. Panic can be raised anywhere, but Recover is only valid in the function called by defer. Let’s start with an example:

func funcA(a) {
	fmt.Println("func A")}func funcB(a) {
	panic("panic in B")}func funcC(a) {
	fmt.Println("func C")}func main(a) {
	funcA()
	funcB()
	funcC()
}
Copy the code

Output:

func A
panic: panic in B

goroutine 1 [running]:
main.funcB(...)
        .../code/func/main.go:12
main.main()
        .../code/func/main.go:20 +0x98
Copy the code

During the running of the program funcB caused panic, resulting in the program crash and abnormal exit. At this point, we can use Recover to restore the program and continue to execute.

func funcA(a) {
	fmt.Println("func A")}func funcB(a) {
	defer func(a) {
		err := recover(a)// If there is a panic error, you can recover it by using recover
		iferr ! =nil {
			fmt.Println("recover in B")}} ()panic("panic in B")}func funcC(a) {
	fmt.Println("func C")}func main(a) {
	funcA()
	funcB()
	funcC()
}
Copy the code

Note:

  1. recover()Must matchdeferUse.
  2. deferBe sure to trigger when possiblepanicStatement before definition.

Go Language basic syntax (2)