Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Golang | Pointers to slices, "slices sometimes altered when passed by value" #97

Open
atc0005 opened this issue Oct 22, 2020 · 0 comments

Comments

@atc0005
Copy link
Owner

atc0005 commented Oct 22, 2020

nanxio.githbooks.io

So if you really want the function to change the content of a slice, you can pass the address of the slice

// https://nanxiao.gitbooks.io/golang-101-hacks/content/posts/pass-slice-as-a-function-argument.html
package main

import (
    "fmt"
)

func addValue(s *[]int) {
    *s = append(*s, 3)
    fmt.Printf("In addValue: s is %v\n", s)
}

func main() {
    s := []int{1, 2}
    fmt.Printf("In main, before addValue: s is %v\n", s)
    addValue(&s)
    fmt.Printf("In main, after addValue: s is %v\n", s)
}  

The result is like this:

In main, before addValue: s is [1 2]
In addValue: s is &[1 2 3]
In main, after addValue: s is [1 2 3]

medium.com/swlh

You can roughly imagine the implementation of the slice as:

type sliceHeader struct {
    Length        int
    Capacity      int
    ZerothElement *byte
}

Passing a slice to a function by value, all the fields are copied and only the data can be modified and accessed from outside through the copy of the pointer.

However, keep in mind that if the pointer is overwritten or modified (due to a copy, an assign, or an append) no change will be visible outside the function, moreover, no change of length or capacity will be visible to the initial function.

The answer to the questions, then, is simple, but hidden inside the implementation of the slice itself:

The pointer to a slice is indispensable when the function is going to modify the structure, the size, or the location in memory of the slice and every change should to be visible to those who call the function.

When we pass a slice to a function as an argument the values of the slice are passed by reference (since we pass a copy of the pointer), but all the metadata describing the slice itself are just copies.

We can modify the data of the slice in the literal function, however if the pointer to the data changes for any reason or the slice metadata is modified, the change can be partially or no visible at all to the outside function.

For example, if the slice gets allocated again, a new location of the memory is used; even if the values are the same, the slice points to a new location and therefore no modification of the values will be visible outside, since the slices are pointing to two different locations (the pointer in the slice copy got overwritten).

calhoun.io

As I mentioned before, when we call append a new slice is created. In the second quiz this new slice still pointed to the same array because it had enough capacity to add the new element, so the array wasn’t changed, but in this example we are adding three elements and our slice doesn’t have enough capacity. Instead, a new array is allocated and our updated slice points to it. When we finally start reversing elements in the slice it is no longer affecting our initial array, but it is instead operating on a completely different one.

References

PlayGround scratch notes:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant