In real development, most cases deal not with a single piece of data, but with multiple pieces of the same type of data. All high-level languages encapsulate corresponding data structures, apis, and so on. In Go, three data structures, array, slice and map, are provided for developers to manage and process set data. Slicing is based on arrays, but is different from arrays. In this note, learn about Go slicing.

Slice structure

In order to make it easier to learn the content of slicing, first of all, let’s have a brief understanding of what the bottom layer of slicing looks like.

Create a slice

The first step in using built-in data structures is to declare create initializations. There are three ways to create slices using make

// Syntax: make([] slice type, length, capacity) Where capacity is optional, capacity >= length

// Create an orthopedic slice with length 5 and capacity 10
intSlice := make([]int.5.10)

// If no capacity value is specified, slices with the same length as the capacity are generated
// Create a string slice of length 10 and capacity 10
stringSlice := make([]string.10)
Copy the code

The PS: make function can also be used to create maps and channels.

Access and modify slice elements consistent with arrays

intSlice[2] = 3
stringSlice[4] = "ji ni tai mei"
// Unassigned elements have a default value of zero

/* If the index accessed exceeds the slice length, the compilation will generate an index out of range exception, such as fmt.println (intSlice[5]) */
Copy the code

Declare and initialize

// Syntax: [] type {initializes the list of elements... }

// Create a string slice of length 4 and capacity 4
stringSlice := []string{"red"."yellow"."blue"."green"}

// Create an empty slice
nilSlice := []int{}
Copy the code

Note the difference between this method and creating an array, where parentheses have specific values.

// Create an array of strings with initialization elements
stringArr := [5]string{"red"."yellow"."blue"."green"}
Copy the code

You can also specify the length.

// Create a string slice of length and capacity 10
stringSlice := []string{9: "rainbow"}
Copy the code

Creates a slice from a slice

slice := []int{1.2.3.4.5.6}

// Syntax: original slice [I :j: capacity] // Capacity is optional
newSlice := slice[1:4] //newSlice is [2, 3, 4]
Copy the code

This creates a slice of length 3 and capacity 5. Note that the length of the slice here is j-i and j is not the index of the ending element. Slices created in this way will share the underlying array, which can be interpreted as “slice from slice”, so the modification of slices will be affected by each other.

slice[2] = 99
fmt.Println(newSlice[1])	// The result is 99
Copy the code

Slice from a slice ↓

Section capacity

One advantage of slicing over arrays is that it can grow dynamically. Grow slices by append(). Before we do that, take a look at the two built-in functions len() and cap(), which return the length of the slice and the capacity of the slice.

// Write a simple function to output the length, capacity, and content of the slice
func echoStringSlice(slice []string) {
	fmt.Printf("len: %d\n".len(slice))
	fmt.Printf("cap: %d\n".cap(slice))
	fmt.Println(slice)
}

// Syntax: append(original slice,... New original) // The second parameter is a variable parameter and can be added as many as you like
func main(a) {
	stringSlice := []string{"red"."yellow"."blue"."green"}
	echoStringSlice(stringSlice)
	fmt.Println("After append...")
	newSlice := append(stringSlice, "rainbow")
	echoStringSlice(newSlice)
}
Copy the code

When compiled and run, the result is

len: 4
cap: 4
[red yellow blue green]
After append.len: 5
cap: 8
[red yellow blue green rainbow]
Copy the code

The append() function will generate a new slice, and the length of the newly generated slice increases. When the capacity of the slice is enough to add new elements, the capacity will not change, but only the length of the slice changes, while when the capacity is insufficient, the underlying array will grow dynamically. The newly generated slice capacity is twice the original capacity (when the original capacity is less than 1024, otherwise the corresponding capacity will be increased by 0.25 growth factor, and the growth factor may become smaller as the value increases)

Pass slices between functions

The space overhead of passing slices between functions is small. The previous simple understanding of the underlying structure of the slice, so when the slice is passed between functions, the slice is about as big as a pointer and two integers combined. When passing arrays between functions, you need to copy the entire array, which is relatively huge in all aspects of overhead. Of course, you can also use Pointers to pass, but there may be security problems if you do not pay attention to pointer operations, and it is not so convenient to grow dynamically.