The usage and nature of Golang slices

Source: Internet
Author: User

Introduction

The slice type of go provides a convenient and efficient way to work with the same type of data series. Slices are somewhat similar to arrays in other languages, but there are some unusual features. This article will delve into the nature of the slice and explain its usage.

Array

The slice of Go is an abstract data type on top of the array, so you must understand the array before you know the slices.

The array type defines the length and element type. For example, [4]int a type represents an array of four integers. The length of the array is fixed, and the length is part of the array type ( [4]int and [5]int is a completely different type). The array can be accessed as a regular index, and the expression s[n] accesses the nth element of the array.

var a [4]inta[0] = 1i: = a[0]//i = = 1

Arrays do not require explicit initialization; The 0 value of an array can be used directly, and an array element is automatically initialized to the 0 value of its corresponding type:

A[2] = = 0, 0 value of type int

The type [4]int corresponds to four consecutive integers in memory:

The array of Go is the value semantics. An array variable represents the entire array, which is not a pointer to the first element (unlike the C-language array). When an array variable is assigned or passed, the entire array is actually copied. (To avoid copying an array, you can pass a pointer to an array, but the array pointer is not an array.) You can treat an array as a special struct whose field names correspond to the index of the array, and the number of members is fixed.

The literal value of the array is like this:

B: = [2]string{"Penn", "Teller"}

Of course, you can also have the compiler count the number of elements in the array literals:

B: = [...] string{"Penn", "Teller"}

Both of these are the b corresponding [2]string types.

Slice

Arrays have a place for them, but arrays are not flexible enough, so arrays in go code are not used much. However, slices are used quite extensively. Slices are built on an array, but provide stronger functionality and convenience.

The slice type is written as the type of the []T T slice element. Unlike the array, the slice type is not given a fixed length.

Slices have a very similar literal value and array literals, but the slices do not have the specified number of elements:

Letters: = []string{"A", "B", "C", "D"}

Slices can be created using built-in functions make , and function signatures are:

Func make ([]t, Len, cap) []t

where T represents the type of slice element being created. makethe function accepts a type, a length, and an optional capacity parameter. makewhen called, an array is allocated internally, and the corresponding slice of the array is returned.

var s []bytes = make ([]byte, 5, 5)//s = = []byte{0, 0, 0, 0, 0}

When the capacity parameter is ignored, it defaults to the specified length. The following is a concise notation:

S: = make ([]byte, 5)

You can use built-in functions len and cap get information about the length and capacity of slices.

Len (s) = = 5cap (s) = = 5

The next two sections discuss the relationship between length and capacity.

The 0 value of the slice is nil . For the 0 value of the slice, len and cap both will return 0.

Slices can also be generated based on existing slices or arrays. The range of the slices is specified by the half-open intervals corresponding to the two indexes separated by colons. For example, an expression b[1:4] creates a slice that references the 1th to 3rd element space of an array b (the corresponding slice has an index of 0 to 2).

B: = []byte{' g ', ' o ', ' l ', ' a ', ' n ', ' G '}//b[1:4] = = []byte{' o ', ' l ', ' a '}, sharing the same storage as B

The start and end indexes of a slice are optional, and they default to zero and the length of the array, respectively.

B[:2] = = []byte{' g ', ' O '}//b[2:] = = []byte{' l ', ' a ', ' n ', ' G '}//b[:] = = b

The following syntax also creates a slice based on an array:

x: = [3]string{"Лайка", "Белка", "Стрелка"}s: = x[:]//a slice referencing the storage of X

The inside of the slice

A slice is a description of an array fragment. It contains a pointer to an array, the length of the fragment, and the capacity (the maximum length of the fragment).

make([]byte, 5)the structure of the tile variable created earlier uses s the following:

The length is the number of elements referenced by the slice. The capacity is the number of elements in the underlying array (starting with the tile pointer). About length and capacity and area will be illustrated in the next example.

We continue to s slice, observe the data structure of the slice and the underlying array it references:

s = s[2:4]

The slice operation does not duplicate the element that the slice points to. It creates a new slice and re-uses the underlying array of the original slice. This makes the slice operation as efficient as the array index. Therefore, modifying an element with a new slice affects the corresponding element of the original slice.

D: = []byte{' R ', ' O ', ' a ', ' d '}e: = d[2:]//E = = []byte{' A ', ' d '}e[1] = ' m '//E = = []byte{' A ', ' m '}//d = = []byte{' R ', ' O ', ' A ', ' m '}

The length of the tile you created earlier is s less than its capacity. We can grow the length of the slice for its capacity:

s = S[:cap (s)]

Slice growth cannot exceed its capacity. Growth exceeding the tile capacity will result in a run-time exception, just as the index of a slice or array is out of range. Similarly, you cannot use an index that is less than 0 to access the element before the slice.

Slice growth (copy and append function)

To increase the capacity of a slice you must create a new, larger tile, and then copy the contents of the original slice to the new slice. The entire technique is a common implementation that supports dynamic array languages. The following example doubles the slice s capacity by creating a new twice-fold slice t , copying s The elements to t , and assigning the values to t s :

T: = make ([]byte, Len (s), (Cap (s) +1) *//+1 in case cap (s) = = 0for I: = Range s {t[i] = S[i]}s = t

The actions copied in the loop can be overridden by the copy built-in function. The copy function copies the elements of the source slice to the destination slice. It returns the number of copied elements.

Func copy (DST, src []t) int

copyThe function supports copying between slices of different lengths (it copies only the length of a shorter slice). In addition, the copy function can correctly handle the case where the source and destination slices overlap.

Using copy functions, we can simplify the code snippet above:

T: = make ([]byte, Len (s), (Cap (s) +1) * *) copy (T, s) s = t

A common operation is to append data to the end of a slice. The following function appends the element to the end of the slice, increasing the capacity of the slice if necessary, and finally returning the updated slice:

func  appendbyte (Slice []byte, data ...byte)  []byte {    m : = len (Slice)     n := m + len (data)     if  n > cap (Slice)  { // if necessary, reallocate         // allocate double what ' s needed, for future  Growth.        newslice := make ([]byte,  (n+1))          copy (Newslice, slice)          SLICE = NEWSLICE    }    SLICE = SLICE[0:N]     copy (slice[m:n], data)     return slice} 

Here's AppendByte a way to use:

P: = []byte{2, 3, 5}p = Appendbyte (p, 7, one, All)//P = = []byte{2, 3, 5, 7, 11, 13}

A similar AppendByte function is more practical because it provides complete control over the growth of the tile capacity. Depending on the program's characteristics, you may want to allocate smaller, larger blocks, or more than a certain size redistribution.

But most programs do not require full control, so go provides a built-in function append for most occasions; its function signature:

Func append (s []t, X ... T) []t

appendThe function is x appended to s the end of the slice and increases the capacity when necessary.

A: = Make ([]int, 1)//A = = []int{0}a = Append (A, 1, 2, 3)//A = = []int{0, 1, 2, 3}

If you are appending one slice to the end of another slice, you need to use ... the syntax to expand the 2nd parameter to the argument list.

A: = []string{"John", "Paul"}b: = []string{"George", "Ringo", "Pete"}a = Append (A, B ...)//equivalent to "append (A, b[0], B[1], b[2]) "//A = = []string{" John "," Paul "," George "," Ringo "," Pete "}

Since the 0 value of the slice is nil used like a zero-length slice, we can declare a slice variable and append it to it in the loop:

Filter returns a new slice holding only//the elements of s that satisfy F () func Filter (s []int, fn func (int) bool) []i NT {var p []int/= = Nil for _, V: = range S {if fn (v) {p = append (P, v)}} Retu RN P}

Possible "traps"

As previously mentioned, the slice operation does not replicate the underlying array. The entire array is saved in memory until it is no longer referenced. Sometimes it is possible for a small memory reference to cause all of the data to be saved.

For example, the FindDigits function loads the entire file into memory, then searches for the first consecutive number, and the final result is returned as a slice.

var digitregexp = RegExp. Mustcompile ("[0-9]+") func finddigits (filename string) []byte {b, _: = Ioutil. ReadFile (filename) return Digitregexp.find (b)}

This code behaves like a description, returning a pointer to []byte an array that holds the entire file. Because the slices refer to the original array, the GC cannot free up the space of the array, and only a few bytes will cause the entire file's contents to remain in memory.

To fix the whole problem, you can copy the data you are interested in to a new slice:

Func copydigits (filename string) []byte {b, _: = Ioutil. ReadFile (filename) b = Digitregexp.find (b) C: = Make ([]byte, Len (b)) copy (c, b) return C}

You can use append the implementation of a more concise version.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.