当前位置: 首页 > 面试题库 >

如何在Go中处理切片的副本?

云默
2023-03-14
问题内容

mapArray是float32的2D切片。我对其进行了复制,因此 无需修改mapArray即可进行复制
。但是,事实并非如此。分配一个值进行Origin修改mapArray

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

这样做将使mapArray[5][5]-1而不是其原始值。

如何制作切片的真实独立副本?

谢谢。

编辑:

// 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
}

问题答案:

2D切片是切片的切片。在您的函数中,您分配一个切片来容纳其他切片,然后为每个切片分配内存来容纳该行数据。要复制它,您需要复制所有这些数据行以及整个切片。

当您说时copy(origins, mapArray),您真正要做的是复制指向原始数据的指针的一部分。但是,您不会复制原始数据。

我建议不要使用嵌套的for循环来复制子切片,而应使用一维切片并创建包装函数以对其进行索引。这样可以提高内存效率,您可以使用内置的copy

这是我会做的一个示例

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))
}

如果您坚持使用2D float32数组,则可以通过以下方法进行复制:

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)
}


 类似资料:
  • 问题内容: 在Go中清除切片的适当方法是什么? 这是我在go论坛中找到的内容: 这样对吗? 为了澄清起见,清除了缓冲区,以便可以重用它。 一个示例是bytes包中的Buffer.Truncate函数。 请注意,Reset只是调用Truncate(0)。因此看来,在这种情况下,第70行将评估:b.buf = b.buf [0:0] http://golang.org/src/pkg/bytes/bu

  • 创建大小为的隐式数组,并创建一个隐式数组的浅副本,指向数组中的前7个元素。 考虑 创建不指向任何隐式数组的零长度切片。 创建长度为2的新隐式数组,并附加值和。slice()指向新的隐式数组,其中

  • 问题内容: 我在网上搜索,但没有找到与i18n和Go相关的任何内容。 我希望使用Go来开发网站。处理国际化的最佳方法是什么? 问题答案: go-i18n具有一些不错的功能: 实施CLDR复数规则。 对带变量的字符串使用文本/模板。 翻译文件是简单的JSON。

  • 切片是Go语言的关键类型之一,它提供了比数组更多的功能。 示例1: package main import "fmt" func main() { // 和数组不同的是,切片的长度是可变的。 // 我们可以使用内置函数make来创建一个长度不为零的切片 // 这里我们创建了一个长度为3,存储字符串的切片,切片元素 // 默认为零值,对于字符串就是""。 s

  • 问题内容: 我是Go编程的新手,我想知道:处理Go程序的配置参数的首选方法是什么(在其他情况下,可能会使用 属性 文件或 ini 文件的东西)? 问题答案: 该JSON格式为我工作得很好。标准库提供了编写缩进数据结构的方法,因此可读性很强。 另请参阅此golang-nuts线程。 JSON的好处在于,它在提供列表和映射语义时(它可能变得非常方便),解析起来相当容易并且易于人类阅读/编辑(这对于许多

  • 问题内容: 假设我有以下长度为3的整数数组: 然后我只抓了前两个项目 在这两种情况下,调用numSlice和nums都会产生3,分别产生2和3。 如果我随后附加到该slice(),则基础数组()现在为。两者的值均保持为3,因为切片的基础数组相同,并且切片的len现在为3。 但是,如果我再次追加到该片(),则该片的基础数组必须更改- 我们看到的情况是,现在numSlice增加了一倍,而len现在是4