Those pits of the go language slice

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

The language developed by the go language for multi-core programming. I feel it is like a modern version of C, simple, concurrent support friendly, easy to deploy. There are only 25 reserved keywords in the Go language, which is enough to indicate that the learning cost is not high.

However, the go language inside slice this thing is not simple. Beginners fall into the pits easily. This document tries to explain the slice.


Let's take a look at some of the basic features of slice.

1. There are three variables within the slice, namely: ptr, Len, cap

PTR is an array of data that is used to store

CAP is the length of the PTR array

Len is the length of the actual array

2. How do I specify the length of the slice at initialization time?

A: = Make ([]int, 10)

When make is here, the 2nd parameter is the length of the slice.

How much does it capacity at this time?

Fmt. Println (Cap (a))

Printed here is 10.

That is, the slice is initialized in this way, and its capacity is the length.

3. How do I specify slice's capacity at initialization time?

A: = Make ([]int, 0, 10)

Parameter 0 We have just said, is the length. 10, is its capacity. So our Len (a) ==0, Cap (a) ==10.

When we write the code, how can we predict the maximum length of a slice in advance, we could optimize our program by specifying capacity way. After all, we've added one more parameter, and we've reduced the overhead of memory allocation releases several times.

4. How do I add data to a slice? What is the relationship between the new slice and the old one when added?

B: = Append (A, 1)

Add a 1 way to slice A, which is the code above. In practice, however, we often use this approach:

A = Append (A, 1)

Now consider this line of code:

B: = Append (A, 1)

What is the relationship between B and a?

This depends on the situation.

If Len (a) +1<=cap (a), at this time an array inside a is still sufficient to store the newly added data, the PTR of B and the PTR of A are the same. At this time: b.ptr = = A.ptr, len (b) = = Len (a) +1, cap (b) = = Cap (a).

5. How do I re-slice a slice? What is the relationship between PTR, Len, cap and the original slice after re-sectioning?

The meaning of the re-slicing here is to take a part of the slice inside the element.

A: = Make ([]int, Ten, c) b: = A[0:5]

As the above code, it is re-slicing. At this time b.ptr = = A.ptr. B.cap = = A.cap. B.len = = 5.


Well, now that you know the underlying properties, you can start practicing practiced hand.

1. See what the following code will output:

Package MainFunc Main () {A: = Make ([]int, 0) B: = Append (A, 1) _ = Append (A, 2) println (B[0])}

We added a 10% to the A to B. This time the output is 1, as if there is no problem. So what does this code output?

Package MainFunc Main () {A: = Make ([]int, 0, ten) b: = Append (A, 1) _ = Append (A, 2) println (B[0])}

Well, it's 2. This I think is the biggest pit when using slice. But understanding the way they are stored inside is not difficult to understand why it is like this.

Finish:

B: = Append (A, 1)

At this time b[0] is indeed 1. But at this time b.ptr = = A.ptr. Because this time cap (a) is 10, enough to store the newly inserted element 1.

Perform:

_ = Append (A, 2)

, the CAP (a) is still 10,len (a) of 0, and the element 2 is inserted into a, making ptr[0]==2. Since B.ptr and A.ptr are the same, the data in B is changed.

2. See what the following code will output:

Package MainFunc Main () {A: = Make ([]int, Ten,] b: = A[5:]println (len (b), Cap (b))}

The answer is: 5 15

Output 5 is because the length of a is 10,b: = a[5:], which is equivalent to a re-slicing, take a 5th element after the value. There are 5 values left after the 5th element, and Len (b) is 5.

Cap (b) Why is it 15?

Because at this point, B.ptr = A.ptr + 5. This is the B internal pointer, which points to the 5th element behind A.ptr. So at this point the cap (b) cannot be 20 because B cannot take advantage of the 5 elements in front of a.

3. If you avoid new slices after re-sectioning, they are not modified? As shown below:

Package Mainimport ("FMT") func doappend (A []int) {_ = append (A, 0)}func main () {a: = []int{1, 2, 3, 4, 5}doappend (A[0:2]) F Mt. Println (A)}
This code will output:

[1 2 0 4 5]
Although we call Doappend, only 2 elements are passed in. But it's got rid of the 3rd element of a. How to avoid it? The answers are as follows:

Package Mainimport ("FMT") func doappend (A []int) {_ = append (A, 0)}func main () {a: = []int{1, 2, 3, 4, 5}doappend (A[0:2:2] ) FMT. Println (A)}

is to add a third capacity parameter when you re-slice the slice.

Doappend (A[0:2:2])

The last 2 is the capacity that specifies the new slice after the re-sectioning. We specify that the capacity is 2, so when the Doappend function is append, it finds that capacity is not 3 enough to reallocate memory. This will not modify the contents of the original slice.

4. Suppose a function must not be called simultaneously by multiple goroutine, how to optimize the memory allocation inside the function?

Package Mainimport ("FMT")//will be called many many times function Func concat (A, B, C, d []byte) []byte {r: = make ([]byte, Len (a) +len (b) +len (c) +len (d)) R = Append (R, a ...) R = Append (r, b ...) R = Append (r, c ...) R = Append (R, D ...) return R}func Main () {for i: = 0; i <; i++ {FMT. Printf ("%s\n", concat ([]byte ("1"), []byte ("2"), []byte ("3"), []byte ("4"))}}

If our concat function will be called many many times, each call makes a new slice, performance will be relatively low, how to optimize it? The case of multithreading is not considered.

Package Mainimport ("FMT") var cache = Make ([]byte, 0, 100)//will be called many many times function Func concat (A, B, C, d []byte) []byte {newlen: = Len (a) +len (b) +len (c) +len (d) if Newlen > Cap (cache) {cache = make ([]byte, newlen*2)}r: = Cache[0:0]r = Append (R, a ...) R = Append (r, b ...) R = Append (r, c ...) R = Append (R, D ...) return R}func Main () {for i: = 0; i <; i++ {FMT. Printf ("%s\n", concat ([]byte ("1"), []byte ("2"), []byte ("3"), []byte ("4"))}}

Very simple, pre-allocating a cache. Each time concat is called, cache[0:0] is used as the starting slice. Because the new R shares PTR and capacity with the cache, subsequent append will not cause the memory to be redistributed unless the pre-allocation is insufficient.


Almost, write so much first. Please correct me if you are wrong, and I hope it will be useful to you.


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.