golang array and slice

The array of golang can be divided into two forms: fixed length and slice.

Fixed length array

Fixed length arrays are declared and initialized with array name: = [length] array member type {initialization value}, or var array name [length] array member type declaration.

Fixed length arrays can be traversed by a for loop or a range for loop:

array1 := [5]int{1, 2, 3, 4, 5}
fmt.Println(array1)
for index, value := range array1 {
    fmt.Println(index, value)
}

The fixed length array adopts the method of value transfer in the process of parameter transfer:

package main

import "fmt"

func print(array [5]int) {
	for index, value := range array {
		fmt.Println(index, value)
	}
}
//You can only modify the value of this local variable array in the function
func change(array [5]int) {
	fmt.Println(&array[0])
	for index, value := range array {
		array[index] = -value
	}
	fmt.Println(array)
}

func main() {
	//Fixed length array
	array1 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(array1)
	for index, value := range array1 {
		fmt.Println(index, value)
	}
	print(array1)
	fmt.Println(&array1[0])
	change(array1)
	fmt.Println(array1)
}

There are two problems. One is that parameter transfer is the way of value transfer, so only the value of local variables can be changed, and the value of the actual parameter that the caller wants to modify cannot be changed.

This problem can be solved by passing in a pointer to a fixed length array:

package main

import "fmt"

//Value passing can only modify the value of the local variable of the formal parameter, but cannot modify the value of the argument
func change(array [5]int) {
	fmt.Println(&array[0])
	for index, value := range array {
		array[index] = -value
	}
	fmt.Println(array)
}
//Pass in a pointer to actually modify the value of the argument
func changeP(array *[5]int) {
	fmt.Println((*array)[1])
	for index, value := range *array {
		(*array)[index] = -value
	}
}

func main() {
	//Fixed length array
	array1 := [5]int{1, 2, 3, 4, 5}
	fmt.Println(array1)
	for index, value := range array1 {
		fmt.Println(index, value)
	}
	fmt.Println(&array1[0])
	change(array1)
	fmt.Println(array1)
	changeP(&array1)
	fmt.Println(array1)
}

Although it is relatively troublesome to use pointers, it still solves the problem of value transmission.

Another problem is difficult to solve: the size of fixed length array needs to be specified in function parameters, so it is difficult to reuse functions with fixed length array as formal parameters

func print(array [5]int) {
	for index, value := range array {
		fmt.Println(index, value)
	}
}
func main(){
	myArray := [3]int{1,2,3}
	print(myArray)
}
//The compiler will report an error: cannot use myArray (type [3]int) as type [5]int in argument to print

Dynamic array can solve this problem.

Dynamic array

Dynamic arrays in golang are similar to vectors in C + +.

Dynamic arrays can be initialized in many ways

//Declare but allocate no space, similar to int *p in c language
var array1 []int
fmt.Println(array1)
//Declare and allocate space for 3 units
var array2 = []int{12, 33, 45}
fmt.Println(array2)
//Use: = declaration
array3 := []int{33, 44, 55, 66}
fmt.Println(array3)
//Use the make function to open up space, similar to malloc function in c language or auto p = new int[5] in c + +
array4 := make([]int, 5)
fmt.Println(array4)

The dynamic array is passed by reference as a function parameter, so the value of the actual parameter can be changed:

package main

import "fmt"

func change(array []int) {
	for index, value := range array {
		array[index] = -value
	}
}

func main() {
	//Dynamic array
	var array2 = []int{12, 33, 45}
	fmt.Println(array2)
	change(array2)
	fmt.Println(array2)
}

Similarly, similar to Vector in C + +, dynamic array contains two concepts: length and capacity. Length is the length currently used and capacity is the capacity currently developed. For example, malloc(10*sizeof(int)) is used to open up 10 int length spaces, but only 5 are used. When the space is exhausted, more space will be reopened. Therefore, capacity always > = length.

You can print out the length and capacity information with the following functions:

func printInfo(array []int) {
	fmt.Printf("lenth = %d,capacity = %d,value = %v\n", len(array), cap(array), array)
}

The following uses the printInfo function to print out dynamic arrays created in different ways:

package main

import "fmt"

func printInfo(array []int) {
	fmt.Printf("lenth = %d,capacity = %d,value = %v\n", len(array), cap(array), array)
}

func main() {
	//Dynamic array
	var array1 []int
	var array2 = []int{12, 33, 45}
	array3 := []int{33, 44, 55, 66}
	array4 := make([]int, 5)
	printInfo(array1)
	printInfo(array2)
	printInfo(array3)
	printInfo(array4)
}

The output results are as follows:

lenth = 0,capacity = 0,value = []
lenth = 3,capacity = 3,value = [-12 -33 -45]
lenth = 4,capacity = 4,value = [33 44 55 66]
lenth = 5,capacity = 5,value = [0 0 0 0 0]

You can see that the dynamic array capacity created by these initialization methods is equal to length.

To create a dynamic array with different capacity and length, you can pass an additional parameter to the make function:

array := make([]int,10,16) //Create a dynamic array with capacity of 16 and length of 10

The dynamic array in go language is also called slice. The expansion rules of slice are similar to those of vector in c + +.

slice expansion

Using the append method, you can insert the value slice name = append(slice name, insert value) at the end of slice, which is very similar to the push of vector_ Back method.

Through this example, you can see the capacity change of slice:

package main

import "fmt"

func printInfo(array []int) {
	fmt.Printf("lenth = %d,capacity = %d,value = %v\n", len(array), cap(array), array)
}

func main() {
	//Dynamic array
	var array1 []int
	printInfo(array1)
	array1 = append(array1, 5)
	printInfo(array1)
	array1 = append(array1, 4)
	printInfo(array1)
	array1 = append(array1, 34)
	printInfo(array1)
	array1 = append(array1, 123)
	printInfo(array1)
	array1 = append(array1, 0)
	printInfo(array1)
	arrt := make([]int, 5, 16)
	printInfo(arrt)
}

The following results will be output:

lenth = 0,capacity = 0,value = []
lenth = 1,capacity = 1,value = [5]
lenth = 2,capacity = 2,value = [5 4]
lenth = 3,capacity = 4,value = [5 4 34]
lenth = 4,capacity = 4,value = [5 4 34 123]
lenth = 5,capacity = 8,value = [5 4 34 123 0]

You can see that each time you append a new element to the dynamic array, the length will increase by 1. When the length is less than or equal to capacity, the capacity will not change. When the capacity is insufficient to accommodate new elements, the capacity will be expanded and the capacity will be doubled.

slice copy

slice can be copied in a way similar to python slicing.

The format is as follows: array2: = array [startIndex: endIndex], the startIndex and endIndex here adopt the left closed and right open interval [startIndex,endIndex), so the endIndex index is not included. At the same time, both startIndex and endIndex here can be omitted. If omitted, startIndex defaults to 0, and if omitted, endIndex defaults to len(array) Therefore, if both startIndex and endIndex are omitted, array2: = array [:] is equivalent to array2: = array.

It should be noted that [startIndex:endIndex] creates slices in this way. The created dynamic array is a shallow copy of the source array. Any modification will directly affect the value of the original array:

array11 := array1[1:3]
printInfo(array11)
array11[0] = 717
printInfo(array1)

The output results are as follows:

lenth = 5,capacity = 8,value = [5 4 34 123 0]
lenth = 2,capacity = 7,value = [4 34]
lenth = 5,capacity = 8,value = [5 717 34 123 0]

You can see that the modification of array11 also changes the value of the internal data of array1.

The deep copy of slice requires the copy method.

arrt := make([]int, 5, 16)
printInfo(arrt)
//Use the copy function to copy the value of the array1[1:3] slice into the arrt
copy(arrt, array1[1:3])
printInfo(arrt)
arrt[1] = 636
printInfo(arrt)
printInfo(array1)

It should be noted that the copy destination address arrt here must use make to open up space in advance, and the space must be larger than the size of the copy source, otherwise a runtime error will occur: index out of range runtime error.

The above code will get the following results:

lenth = 5,capacity = 16,value = [0 0 0 0 0]
lenth = 5,capacity = 16,value = [4 34 0 0 0]
lenth = 5,capacity = 16,value = [4 636 0 0 0]
lenth = 5,capacity = 8,value = [5 4 34 123 0]

It can be seen that the slice values are successfully copied to the new array, and the changes will no longer affect the copy source array, and the deep copy is successfully realized.

Tags: Go Back-end

Posted on Fri, 22 Oct 2021 01:50:27 -0400 by chancho