The difference between Go new and make && arrays and slices

Source: Internet
Author: User
Tags readfile
This is a creation in Article, where the information may have evolved or changed.

The difference between Go new and make and the nature of slices

Make, new operation

Make is used for memory allocations of built-in types (map, slice, and channel). New is used for various types of memory allocations.

The built-in function new is essentially the same as the function of the same name in other languages: new (T) allocates 0 of the memory space of the T type populated by the value, and returns its address, which is a value of type *t. In the terms of go, it returns a pointer to the 0 value of the newly assigned type T. One thing is very important:

New returns a pointer.

The built-in function make (T, args) has a different function than new (t), making can only create slice, map, and channel, and returns a T type with an initial value (not 0) instead of *t. Essentially, the reason that these three types are different is that references to data structures must be initialized before they are used. For example, a slice is a three-item descriptor that contains pointers, lengths, and capacities to the data (internal array), and slice is nil until those items are initialized. For slice, map, and channel, make initializes the internal data structure and populates the appropriate values.

Make returns the initialized (not 0) value.

The diagram below explains in detail the difference between new and make.

Make and new correspond to the underlying memory allocations

Go 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, the [4]int 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 are completely different types). 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, int 类型的零值

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 formulations, B are corresponding to the [2]string type.

Go slices

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 []t, T is the type of the 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, and function signatures are:

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

where T represents the type of slice element being created. The function make accepts a type, a length, and an optional capacity parameter. When make is 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 the built-in function Len and the cap to get information about the length and capacity of a slice.

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, both Len and Cap 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, the expression B[1:4] creates a slice that references the 1th to 3rd element space of 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 nature of the slices

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).

The structure of the tile variable s that you created earlier with make ([]byte, 5) is as follows:

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 slice s, observing the slice's data structure 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 previously created slice S is 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 first creating a new twice-fold tile T, copying the elements of S to T, and assigning T to S:

t := make([]byte, len(s), (cap(s)+1)*2) // +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

The copy function supports copying between slices of different lengths (it copies only the length of a shorter slice). In addition, the copy function correctly handles overlapping of source and destination slices.

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

t := make([]byte, len(s), (cap(s)+1)*2)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)*2)        copy(newSlice, slice)        slice = newSlice    }    slice = slice[0:n]    copy(slice[m:n], data)    return slice}

Here is a usage of appendbyte:

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

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

However, 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

The Append function appends x to the end of the slice s 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 expands the 2nd parameter to a parameter list.

Since the 0 value of the slice nil is used like a zero-length slice, we can declare a slice variable and append the data 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) []int {    var p []int // == nil    for _, v := range s {        if fn(v) {            p = append(p, v)        }    }    return 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, and the returned []byte points to 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}

Reproduced:

Https://blog.go-zh.org/go-slices-usage-and-internals

Http://www.cnblogs.com/junneyang/p/6070238.html

==========end==========

Related Article

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.