faisal_kk
faisal_kk

Reputation: 1073

Out growing Slice and Underlying array

I have an array and a slice pointing to it, like shown as follows:

package main

import "fmt"

func main() {

    array_str := []string{"0a","1b","2c","3d","4e"}
    slice_str:=array_str[1:4]
    fmt.Println("Initially :")
    fmt.Println("Printing 1 :Array :",array_str)
    fmt.Println("Printing 1 :Slice:",slice_str)

    //Step 1.Changing Slice and it get reflected in array
    fmt.Println("\nAfter Alteration:")
    slice_str[0]="alterd_1b"
    fmt.Println("Printing 2 :Array :",array_str)
    fmt.Println("Printing 2 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of         slice_str:",cap(slice_str),"len of  array_str:",len(array_str))

    //Step 2.appending to slice and it get reflected

    slice_str = append(slice_str,"apnded_elemnt")
    fmt.Println("\nAfter Apending:")
    fmt.Println("Printing 3 :Array :",array_str)//"4e" is replaced with "apnded_elemnt" in array !!
    fmt.Println("Printing 3 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of   slice_str:",cap(slice_str),"len of  array_str:",len(array_str))

    //Step 3.Again appending to slice so that lentght of slice is growing further to  underlaying array
    slice_str = append(slice_str,"outgrown_elemnt")
    fmt.Println("\nAfter OUT GROWING:")
    fmt.Println("Printing 4 :Array :",array_str)//obeviously out grown elemnt not added to array that is fine
    fmt.Println("Printing 4 :Slice:",slice_str)
    fmt.Println("len of  slice_str:",len(slice_str)," cap of slice_str:",cap(slice_str),"len of  array_str:",len(array_str))
    //How Capacity Become 8 here ???

    //Step 4 .Now Changing Slice element which is in Range of array to verify it reflect on array:
    fmt.Println("\nAfter Post out grown Alteration:")
    slice_str[0]="again_alterd_1b"
    fmt.Println("Printing 2 :Array :",array_str)//Change in slice is not reflectd in array .Why ?
    fmt.Println("Printing 2 :Slice:",slice_str)
}

Playground: http://play.golang.org/p/3z52HXHQ7s

Questions:

  1. In Step 3: why does cap of the slice jumped from 4 to 8?

  2. In Step 4: after the slice is out grown, changes to the element of the slice, which is in the range of the array, is not reflected to the array and vice versa. Why is it not happening after it is grown out? What actually happens when the slice grows out?

Upvotes: 1

Views: 910

Answers (2)

julienc
julienc

Reputation: 20305

The capacity is multiplied by 2 because it is less consuming. Indeed, memory allocation is very consuming, and it's better to allocate a lot of memory a single time than exactly what is needed every time.

Let's just compare, first with a simple example using the concatenation: every time, Go allocates just what is needed.

var n = time.Now()
var s = ""
for i := 0; i < 1000000; i++ {
    s += "a"
}
fmt.Println(time.Now().Sub(n))
// 47.7s

Now, let's do the same but this time using the bytes.Buffer type:

var n = time.Now()
var b = bytes.NewBufferString("")
for i := 0; i < 1000000; i++ {
    b.WriteString("a")
}
fmt.Println(time.Now().Sub(n))
// 18.5ms

The difference is the way Buffer allocates memory: when there is not enough capacity, it allocates twice the current capacity:

buf = makeSlice(2*cap(b.buf) + n)

Source

This works the same with slices (I was just not able to find the source code to prove it...). So yes, you may be losing some space, but this is for a much better efficiency!


You're second question is a bit more tricky for me, so I hope @Volker's answer will be clear enough for you !

Upvotes: 2

Volker
Volker

Reputation: 42413

See here: http://blog.golang.org/slices

Short answers: 1) it grows by doubling (while short). If you append once you might append a second time too and this avoids allocations. 2) That's how slice growing works. An array cannot grow, so a new, larger array is allocated, the old one copied and you are handed a slice pointing to the larger copy.

(The documentation on the golang.org website is really helpful, readable, short and precise. I'd like to recommend to look at golang.org first before asking here.)

Upvotes: 5

Related Questions