Go sections: Usage and nature

2011/01/05

introduction

Go slice type is the same type of data processing sequence provides a convenient and efficient manner. Slice somewhat similar to the array in other languages, but there are some unusual characteristics. This article will delve nature slices, and explain its use.

Array

Go slices abstract data types on the array, the array must first be understood before understanding slice.

Array type defines the length and element type. For example,  [4]int type represents an array of four integers. Length of the array is fixed, a part of the length (array type  [4]int and  [5]int are completely different types). Arrays can be accessed in conventional indexing expression  s[n] n-th element array accesses.

var in [4] int 
a [0] = 1 
i: = a [0] 
// == 1 and

No explicit initialization array; array is zero value can be used directly, the array elements are automatically initialized to its zero value corresponding to the type of:

// a [2] == zero value 0, int type

Type  [4]int memory corresponding to four consecutive integers:

Go array value semantics. Represents a variable array of the entire array, it is not a pointer to the first element (array unlike the C language). When an array variable is assigned or to be delivered, you will actually copy the entire array. (To avoid copying the array, you can pass a pointer to an array, but the array is not a pointer array.) Can be viewed as a special array of struct, field names corresponding to the structure of the array index, while a fixed number of members.

Literal array like this:

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

Of course, you can let the compiler count the number of elements in an array literal:

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

Both versions,  b are the corresponding  [2]string type.

slice

Although there are an array where they apply, but the array is not flexible enough, so Go array used in the code are not many. However, the slice is used quite widely. Slice-based array to build, but offers greater functionality and convenience.

Slice type of wording is  []T ,  T is the type of slice elements. And an array of difference is that slice type is not given a fixed length.

Slice literals and array literals like, but do not specify a slice number of elements:

letters := []string{"a", "b", "c", "d"}

Slice can use built-in functions  make to create, function signature is:

func make([]T, len, cap) []T

Where T represents the type of slice elements were created. Function  make accepts a type, a length, and an optional capacity parameter. Call  make , the internal assigns an array, then returns an array of corresponding slices.

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

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

s := make([]byte, 5)

Can use built-in functions  len and the  cap acquisition of the slice length and capacity information.

len (s) == 5 
head (s) == 5

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

Zero value slices  nil . For a slice of zero value,  len and  cap it will return 0.

Slice may be generated based on existing chips or arrays. Range sliced by a corresponding index divided by a colon two half-open interval specified. For example, expression of  b[1:4]a slice of a reference array to create  b a first spatial element 1-3 (index corresponding slices from 0 to 2).

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

Start and end index sections are optional; default they are zero and the array length.

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

The following syntax is also based on an array to create a slice:

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

Insider slices

It describes an array slice is a fragment. It contains pointers to arrays, (the maximum length of the fragment) fragment length, and capacity.

Previously used  make([]byte, 5) slice variable created  s structured as follows:

Length is the number of elements in the slice reference. Capacity of the underlying array element number (starting from the slice pointers). Regarding the length and volume and area will be described next example.

We continue to  s slice, slice of observational data structure and its underlying array references:

s = s[2:4]

Slicing operation does not copy the elements sliced ​​points. It creates a new slice and reuse the original slice of the underlying array. This enables the same operation and efficient slicing array index. Thus, by modifying a new element to the corresponding slice will affect elements of the original slices.

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'}

Previously created slice  s length less than its capacity. We can increase the length of its slice capacity:

s = s[:cap(s)]

Slice growth does not exceed its capacity. Increase capacity beyond the slice will cause an exception, as the index is out of range or array slice cause abnormal as running. Similarly, the index is less than zero can not be used to access the elements before slicing.

Growth sections (copy and append function)

To increase the capacity of a slice must create a new, higher-capacity chips, and then copy the contents of the original slice to a new slice. The entire technology are some of the common implementation supports dynamic arrays languages. The following example will slice  s capacity doubled, to create a new slice a two-fold volume  t , copying  s elements to  t , and then  tassigned to  s :

t := make([]byte, len(s), (cap(s)+1)*2) // +1 in case cap(s) == 0
for i := range s {
        t[i] = s[i]
}
s = t

循环中复制的操作可以由 copy 内置函数替代。copy 函数将源切片的元素复制到目的切片。 它返回复制元素的数目。

func copy(dst, src []T) int

copy 函数支持不同长度的切片之间的复制(它只复制较短切片的长度个元素)。 此外, copy 函数可以正确处理源和目的切片有重叠的情况。

使用 copy 函数,我们可以简化上面的代码片段:

t := make([]byte, len(s), (cap(s)+1)*2)
copy(t, s)
s = t

一个常见的操作是将数据追加到切片的尾部。下面的函数将元素追加到切片尾部, 必要的话会增加切片的容量,最后返回更新的切片:

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)*2)
        copy(newSlice, slice)
        slice = newSlice
    }
    slice = slice[0:n]
    copy(slice[m:n], data)
    return slice
}

下面是 AppendByte 的一种用法:

p := []byte{2, 3, 5}
p = AppendByte(p, 7, 11, 13)
// p == []byte{2, 3, 5, 7, 11, 13}

类似 AppendByte 的函数比较实用,因为它提供了切片容量增长的完全控制。 根据程序的特点,可能希望分配较小的活较大的块,或则是超过某个大小再分配。

但大多数程序不需要完全的控制,因此Go提供了一个内置函数 append , 用于大多数场合;它的函数签名:

func append(s []T, x ...T) []T

append 函数将 x 追加到切片 s 的末尾,并且在必要的时候增加容量。

a := make([]int, 1)
// a == []int{0}
a = append(a, 1, 2, 3)
// a == []int{0, 1, 2, 3}

如果是要将一个切片追加到另一个切片尾部,需要使用 ... 语法将第2个参数展开为参数列表。

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"}

由于切片的零值 nil 用起来就像一个长度为零的切片,我们可以声明一个切片变量然后在循环 中向它追加数据:

// Filter returns a new slice holding only
// the elements of s that satisfy fn()
func Filter(s []int, fn func(int) bool) []int {
    var p []int // == nil
    for _, v := range s {
        if fn(v) {
            p = append(p, v)
        }
    }
    return p
}

可能的“陷阱”

正如前面所说,切片操作并不会复制底层的数组。整个数组将被保存在内存中,直到它不再被引用。 有时候可能会因为一个小的内存引用导致保存所有的数据。

例如, FindDigits 函数加载整个文件到内存,然后搜索第一个连续的数字,最后结果以切片方式返回。

var digitRegexp = regexp.MustCompile("[0-9]+")

func FindDigits(filename string) []byte {
    b, _ := ioutil.ReadFile(filename)
    return digitRegexp.Find(b)
}

这段代码的行为和描述类似,返回的 []byte 指向保存整个文件的数组。因为切片引用了原始的数组, 导致 GC 不能释放数组的空间;只用到少数几个字节却导致整个文件的内容都一直保存在内存里。

要修复整个问题,可以将感兴趣的数据复制到一个新的切片中:

func CopyDigits(filename string) []byte {
    b, _ := ioutil.ReadFile(filename)
    b = digitRegexp.Find(b)
    c := make([]byte, len(b))
    copy(c, b)
    return c
}

可以使用 append 实现一个更简洁的版本

Guess you like

Origin www.cnblogs.com/qiaoyanlin/p/12005226.html