How to work with duplicate of a slice in Go?

2019-02-19 18:49发布

mapArray is a 2D slice of float32. I make a copy of it so I can work on the copy without modifying mapArray. However, it's not the case. Assigning a value to Origin modifies mapArray.

origins := it.Empty2DArray(len(mapArray))
copy(origins, mapArray)
origins[5][5] = -1

Doing that makes mapArray[5][5] to be -1 instead of its original value.

How can i make a true independent copy of the slice?

Thanks.

Edit:

// Empty2DArray returns a zeroed 2D array.
func Empty2DArray(arraySize int) [][]float32 {
    emptyArray := make([][]float32, arraySize)
    for y := 0; y < arraySize; y++ {
        row := make([]float32, arraySize)
        for x := 0; x < arraySize; x++ {
            row[x] = 0
        }
        emptyArray[y] = row
    }
    return emptyArray
}

标签: go slice
1条回答
Anthone
2楼-- · 2019-02-19 19:23

A 2D slice is a slice of slices. In your function you allocate one slice to hold the others, then for each slice you allocate memory to hold that line of data. To copy this, you need to copy all of these data lines plus the overall slice.

When you say copy(origins, mapArray), what you really do is make a copy of a slice of pointers to the original data. You do not however copy the original data.

I would suggest that instead of doing a nested for-loop for copying the sub-slices, instead just use a one-dimensional slice and create wrapper functions to index into it. This is more memory efficient and you can use the built-in copy.

Here is a sample of what I would do instead:

package main

import "fmt"

type squareMat struct {
    size int
    data []float32
}

func newSquareMat(size int) *squareMat {
    return &squareMat{
        size: size,
        data: make([]float32, size*size),
    }
}

func (s *squareMat) get(i, j int) float32 {
    return s.data[i+j*s.size]
}

func (s *squareMat) set(i, j int, to float32) {
    s.data[i+j*s.size] = to
}

func (s *squareMat) copy() *squareMat {
    c := newSquareMat(s.size)
    copy(c.data, s.data)
    return c
}

func main() {
    m := newSquareMat(5)
    m.set(2, 3, 1.5)
    n := m.copy()
    n.set(2, 3, 99)
    fmt.Println(m.get(2, 3))
    fmt.Println(n.get(2, 3))
}

If you instead insist on using 2D float32 arrays, here is how to copy that:

package main

import "fmt"

func copy2D(x [][]float32) [][]float32 {
    c := make([][]float32, len(x))
    for i := range c {
        c[i] = make([]float32, len(x[i]))
        copy(c[i], x[i])
    }
    return c
}

func main() {
    a := [][]float32{
        []float32{1, 2, 3},
        []float32{4, 5, 6},
        []float32{7, 8, 9},
    }
    b := copy2D(a)
    b[1][1] = 99
    fmt.Println(a)
    fmt.Println(b)
}
查看更多
登录 后发表回答