SoFunction
Updated on 2025-03-05

A brief discussion on whether modifying the value of Go slice will overwrite the value of the array

Slices and arrays

Array

An array is a sequence of numbers and fixed lengths of data items with the same unique type

Array declaration

var identifier [len]type

slice

A slice is a reference to a continuous fragment of an array, a slice is a reference type, and a slice is a pointer.

A slice is an array of variable length.

Slice statement

var identifier []type

Slice initialization

var slice1 []type = arr[start:end]

Modify the value of the slice

Modify the value of the slice to overwrite the value of the array

Code

package main

import "fmt"

func main() {
  arr := [5]int{1,2,3,4,5}
  ("slice modification before: array=%v len=%d cap=%d\n", arr, len(arr), cap(arr))
  
  s := arr[0:3]
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
  s = append(s, 6,10) 
  
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
  ("slice modification: array=%v len=%d cap=%d\n", arr, len(arr), cap(arr))
}

result

slice modification before: array=[1 2 3 4 5] len=5 cap=5
len=3 cap=5 ptr=0xc00000c300 slice=[1 2 3]
len=5 cap=5 ptr=0xc00000c300 slice=[1 2 3 6 10]
slice modification: array=[1 2 3 6 10] len=5 cap=5

Since the capacity of the underlying array has not exceeded, the address remains unchanged, and the array is still the original array, modifying the slice will overwrite the value of the array.

Modify the slice not to overwrite the value of the array

Code

package main

import "fmt"

func main() {
  arr := [5]int{1,2,3,4,5}
  ("slice modification before: array=%v len=%d cap=%d\n", arr, len(arr), cap(arr))
  
  s := arr[0:3]
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
  s = append(s, 6,10,11) 
  
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
  ("slice modification: array=%v len=%d cap=%d\n", arr, len(arr), cap(arr))
}

result

slice modification before: array=[1 2 3 4 5] len=5 cap=5
len=3 cap=5 ptr=0xc00000c300 slice=[1 2 3]
len=6 cap=10 ptr=0xc0000141e0 slice=[1 2 3 6 10 11]
slice modification: array=[1 2 3 4 5] len=5 cap=5

Exceeding the capacity of the underlying array, the address changes, and a new array will be allocated, and the returned slice points to the new array, and the value of the old array has not been modified.

Slice expansion mechanism

Slice decimal 1024

Code

package main

import "fmt"

func main() {
  arr := [5]int{1,2,3,4,5}
  
  s := arr[0:3]
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
  s = append(s, 6,10,11) 
  
  ("len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
}

result

before: len=3 cap=5 ptr=0xc00000c300 slice=[1 2 3]
after: len=6 cap=10 ptr=0xc0000141e0 slice=[1 2 3 6 10 11]

The capacity of this slice is twice the capacity of the source slice

Slice is not less than 1024

Code

package main

import "fmt"

func main() {
  arr := [1024]int{1,2,3,...,1024}
  s := arr[0:] 
  ("before: len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)

  s = append(s, 1025)
  ("after: len=%d cap=%d ptr=%p slice=%v\n", len(s), cap(s), s, s)
}

result

before: len=1024 cap=1024 ptr=0xc000112000 slice=[1 2 3 ... 1024]
after: len=1025 cap=1280 ptr=0xc00012c000 slice=[1 2 3 ... 1024 1025]

The slice capacity increases by 1/4 to the original slice capacity

Slice source code

If the capacity of the slice is not enough, the function growslice will be called to expand the capacity

//  go1.16.6 src/runtime/
func growslice(et *_type, old slice, cap int) slice {
    ... // code
    newcap := 
    doublecap := newcap + newcap
    if cap > doublecap {
        newcap = cap
    } else {
        if  < 1024 {
            newcap = doublecap
        } else {
            // Check 0 < newcap to detect overflow
            // and prevent an infinite loop.
            for 0 < newcap && newcap < cap {
                newcap += newcap / 4
            }
            // Set newcap to the requested cap when
            // the newcap calculation overflowed.
            if newcap <= 0 {
                newcap = cap
            }
        }
    }
    // Calculate the size of memory to be allocated based on the slice type and capacity    var overflow bool
    var lenmem, newlenmem, capmem uintptr

    switch {
    ... // code
    }

    ... // code
    // Move the data of the old slice to the address opened by the new slice    memmove(p, , lenmem)

    return slice{p, , newcap}
}

Rules for slice expansion

  • If the capacity of the original array has not been touched after expansion, the pointer in the slice still points to the original array. If the capacity of the original array exceeds the capacity after expansion, a new piece of memory will be opened and the original value will be copied. This situation will not affect the original array at all.
  • If the capacity of the slice is less than 1024, then its capacity is multiplied by 2 when expanding; once the capacity exceeds 1024, the growth factor becomes 1.25, that is, one-quarter of the original capacity is added each time.

This is the article about whether modifying the value of Go slices will overwrite the value of an array. This is all about this article. For more related Go slices to overwrite the value of an array, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!