What is the mechanism for using append to add to Go?

Suppose I have a slicetype slice int. When declaring, I set the third argument size, which I assume reserves memory for at least sizeints by setting the capslice parameter .

slice:=make([]int,0,size)

Now suppose I have an integer variable value. To add it to the fragment at the end, I use

slice=append(slice,value)

If the number of elements currently in the slice is less than size, then there is no need to copy the entire base array to a new location to add a new element.

Also, if I want to add valuein slice, as suggested here and here , I use

slice=append([]int{value},slice...)

My question is: what happens in this case? If the number of elements is even less than sizehow are the elements stored in memory? Assuming continuous allocation when calling a function make(), are all existing elements offset to the right to free up the first space for the value? Or is the memory redistributed and all the elements copied?

The reason for the request is that I would like my program to be as fast as possible, and I would like to know if this is a possible reason for its slowdown. If so, is there an alternative way to add that will be more time efficient?

+4
source share
2 answers

With repetition and copying

append() . () .

, ( "" ), , , , 0 th. . :

func prepend(dest []int, value int) []int {
    if cap(dest) > len(dest) {
        dest = dest[:len(dest)+1]
        copy(dest[1:], dest)
        dest[0] = value
        return dest
    }

    // No room, new slice need to be allocated:
    // Use some extra space for future:
    res := make([]int, len(dest)+1, len(dest)+5)
    res[0] = value
    copy(res[1:], dest)
    return res
}

:

s := make([]int, 0, 5)
s = append(s, 1, 2, 3, 4)
fmt.Println(s)
s = prepend(s, 9)
fmt.Println(s)
s = prepend(s, 8)
fmt.Println(s)

( Go Playground):

[1 2 3 4]
[9 1 2 3 4]
[8 9 1 2 3 4]

. , , :

res := append([]int{value}, dest...)

, : ([]int{value}), append() , dest.

( make(), ), value dest ( ).

, . , / , node, root, root ( ).

container/list.

, .

( ), , . , , 1 .

, :

var backing = make([]int, 15) // 15 elements
var start int

func prepend(dest []int, value int) []int {
    if start == 0 {
        // No more room for new value, must allocate bigger backing array:
        newbacking := make([]int, len(backing)+5)
        start = 5
        copy(newbacking[5:], backing)
        backing = newbacking
    }

    start--
    dest = backing[start : start+len(dest)+1]
    dest[0] = value
    return dest
}

/:

start = 5
s := backing[start:start] // empty slice, starting at idx=5
s = append(s, 1, 2, 3, 4)
fmt.Println(s)
s = prepend(s, 9)
fmt.Println(s)
s = prepend(s, 8)
fmt.Println(s)

// Prepend more to test reallocation:
for i := 10; i < 15; i++ {
    s = prepend(s, i)
}
fmt.Println(s)

( Go Playground):

[1 2 3 4]
[9 1 2 3 4]
[8 9 1 2 3 4]
[14 13 12 11 10 8 9 1 2 3 4]

: , backing !. , , backing +1 , , . , .

, backing, , "".

: , .

, preand !

, "" , append(s, value). .

, (, , , , "" preand), ( for range , ), wise preanding , append().

. , , , :

for i := len(s) - 1; i >= 0; i-- {
    // do something with s[i]
}

: , . , reslicing +1, +len(values), dst[0] = value, copy(dst, values).

+4

"prepend" , Go , ( ).

, , .

slice = append([]int{value}, slice...)

  • value (, )
  • (start = 0, size = 1, alloc = 1)
  • append
  • append , ,

/ , deque. , Go , ( Go - ).

deque , (, , - , , ).


Go, Go... deque ( )

type Deque struct {
    buffer  []interface{}
    f, b, n int
}

func (d *Deque) resize() {
    new_buffer := make([]interface{}, 2*(1+d.n))
    j := d.f
    for i := 0; i < d.n; i++ {
        new_buffer[i] = d.buffer[j]
        d.buffer[j] = nil
        j++
        if j == len(d.buffer) {
            j = 0
        }
    }
    d.f = 0
    d.b = d.n
    d.buffer = new_buffer
}

func (d *Deque) push_back(x interface{}) {
    if d.n == len(d.buffer) {
        d.resize()
    }
    d.buffer[d.b] = x
    d.b++
    if d.b == len(d.buffer) {
        d.b = 0
    }
    d.n++
}

func (d *Deque) push_front(x interface{}) {
    if d.n == len(d.buffer) {
        d.resize()
    }
    if d.f == 0 {
        d.f = len(d.buffer)
    }
    d.f--
    d.buffer[d.f] = x
    d.n++
}

func (d *Deque) pop_back() interface{} {
    if d.n == 0 {
        panic("Cannot pop from an empty deque")
    }
    if d.b == 0 {
        d.b = len(d.buffer)
    }
    d.b--
    x := d.buffer[d.b]
    d.buffer[d.b] = nil
    d.n--
    return x
}

func (d *Deque) pop_front() interface{} {
    if d.n == 0 {
        panic("Cannot pop from an empty deque")
    }
    x := d.buffer[d.f]
    d.buffer[d.f] = nil
    d.f++
    if d.f == len(d.buffer) {
        d.f = 0
    }
    d.n--
    return x
}
+3

Source: https://habr.com/ru/post/1668135/


All Articles