去切片突变最佳实践

时间:2019-12-02 14:08:46

标签: go slice

要知道底层原始数组是否正在发生突变,或者在传递切片时是否知道其原始数组的副本是否正在发生突变,这并不是很可预测的

a = [3]int {0, 1, 2}
s = a[:]
s[0] = 10
a[0] == s[0] // true


s = append(s, 3)
s[0] = 20
a[0] == s[0] // false

让我们今天说我进行了这种处理

a = [3]int {0, 1, 2}
s = some_func(a[:]) // returns slice
process(s) // a is getting mutated because so far some_func hasn't caused the underlying array to be copied

现在是明天

a = [3]int {0, 1, 2}
s = some_func(a[:]) // returns slice, does append operations
process(s) // a is not getting mutated because some_func caused the underlying array to be copied

那么切片的最佳实践是什么?

1 个答案:

答案 0 :(得分:1)

如果函数确实确实修改了切片的基础数组,并且承诺总是 修改了基础数组,则该函数通常应采用切片按值指定参数,而不返回更新的切片: 1

// Mutate() modifies (the backing array of) s in place to achieve $result.
// See below for why it returns an int.
func Mutate(s []T) int {
    // code
}

如果函数可以在适当的位置修改基础数组,但可能返回使用新数组的切片,则该函数应返回新的切片值,或采用指向切片的指针:

// Replace() operates on a slice of T, but may return a totally new
// slice of T.
func Replace(s []T) []T {
    // code
}

此函数返回时,您应该假定基础数组(如果拥有)可以使用或可以不使用:

func callsReplace() {
    var arr [10]T
    s := Replace(arr[:])
    // From here on, do not use variable arr directly as
    // we don't know if it is s's backing array, or not.

    // more code
}

但是Mutate()承诺会就地修改数组。请注意,Mutate通常需要返回实际更新的数组元素的数量:

func callsMutate() {
    var arr [10]T
    n := Mutate(arr[:])
    // now work with arr[0] through arr[n]

    // more code
}

1 当然,它可以使用指向数组对象的指针,并在适当的位置修改数组,但是灵活性不强,因为随后将数组大小转换为类型。