A pit of reference encountered in slice processing in golang

Keywords: Go

Two days ago, I encountered a pit when I was working on a sweeping robot algorithm.

Part of the code is as follows:

func move2(startPoint Point) [][]Point {
    allFootPrint := [][]Point{{startPoint}}
    for i := 0; i < N; i++ {
        allNewFootPrint := make([][]Point, 0)
        for len(allFootPrint) > 0 {
            curFootPrint := allFootPrint[len(allFootPrint)-1]
            allFootPrint = allFootPrint[:len(allFootPrint)-1]
            last := curFootPrint[len(curFootPrint)-1]
            for _, d := range directions {
                nextPoint := Point{last.X + d[0], last.Y + d[1]}
                if !inArray(nextPoint, curFootPrint) {
                    // A copy of the data must be copied, otherwise path duplication will occur.
                    newCurFootPrint := make([]Point, len(curFootPrint))
                    copy(newCurFootPrint, curFootPrint)

                    allNewFootPrint = append(allNewFootPrint, append(newCurFootPrint, nextPoint))
                }
            }
        }
        allFootPrint = allNewFootPrint
    }
    return allFootPrint
}

This annotation is critical. If it is not copied, it will lead to two consecutive identical paths in allNewFootPrint, and not all paths have problems. It will only occur after the end of a cycle and the beginning of a new cycle. It took half a day to find out the problem.

Now take this question out and share it with you.

package main

import "fmt"

func main() {
    a := []int{1,2,3,4,5,6}
    x := a[:2]
    x = append(x, 9)
    fmt.Println(x)
    fmt.Println(a)
}

Output:

[1 2 9]
[1 2 9 4 5 6]

The above operation is very simple, that is to take the first two from a slice, and then add a number 9 into it.
As a result, we found that x was correct, but slice a changed accordingly.
This shows that x is actually only a reference to slice a. Any change to x will affect a.
This is a huge pit, and the problem of robots is also here.
Only copy ing a new slice can solve this problem.

package main

import "fmt"

func main() {
    a := []int{1,2,3,4,5,6}

    c := make([]int, 2)
    copy(c, a[:2])

    c = append(c, 9)
    fmt.Println(c)
    fmt.Println(a)
}

Output:

[1 2 9]
[1 2 3 4 5 6]

Posted by MartinGr on Thu, 03 Oct 2019 08:43:57 -0700