go - Go 切片变异最佳实践
问题描述
要知道底层的原始数组是否发生了变异,或者当切片被传递时,原始数组的副本是否发生了变异,这并不是很容易预测
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
// 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当然,它可以使用一个指向数组对象的指针,并就地修改数组,但这不太灵活,因为数组大小随后被烘焙到类型中。
推荐阅读
- python - 如何仅在模型更新时将自定义字段验证器应用于模型?
- php - 如何在 wp-admin/users.php 页面添加/删除角色时触发“profile_update”挂钩?(或在这种情况下使用什么其他钩子)
- json - Talend - 将字符串转换为 JSON 字符串数组
- algorithm - 如何在立方体图案中找到立方体的数量,其中中心的立方体沿着手臂有 4 个立方体
- batch-file - 在不使用输入文件的情况下向“plink.exe”发送命令
- mysql - MySQL 查询然后更新
- c++ - 将集合的第一个第 n 个值复制到 C++ 中的向量的简单方法
- c++ - GNU c++ 编译器选项来标记 if (a = b)
- machine-learning - AUTOENCODER - 重塑数据以获得更深的架构?
- unity3d - 如何在另一个脚本中使用gameObject?