Функция
append
добавляет элементы в срез и возвращает новый срез. Однако есть нюанс: если емкость исходного среза достаточна, append
изменит его. Если нет — создаст новый срез с новым базовым массивом.- Code: Select all
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
newSlice := append(slice, 4)
slice[0] = 99
fmt.Println(newSlice)
}
Возможные проблемы:
- Если несколько срезов ссылаются на один базовый массив, изменение одного среза может повлиять на другие;
- Если вы сохраняете ссылку на большой массив через под-срез, это может предотвратить сборку мусора для неиспользуемых данных;
- Если вы предполагаете, что append всегда создает новый срез, это может привести к неожиданному поведению.
Как избежать проблем?
- Создавать копии срезов
Если вам нужно изменить срез, не затрагивая исходный, используйте функцию copy или явно создавайте новый срез.- Code: Select all
package main
import "fmt"
func main() {
original := []int{1, 2, 3}
copied := make([]int, len(original))
copy(copied, original)
copied[0] = 99
fmt.Println(original)
fmt.Println(copied)
}
- Используйте полное выражение среза
Если вы создаете под-срез и хотите контролировать его емкость, используйте полное выражение среза (slice[low:high:max]).- Code: Select all
package main
import "fmt"
func main() {
original := []int{1, 2, 3, 4, 5}
subslice := original[1:4:4]
subslice = append(subslice, 6)
fmt.Println(original)
fmt.Println(subslice)
}
- Проверяйте емкость перед использованием
append
Если вы хотите быть уверены, что append не изменит исходный срез, проверьте его емкость.- Code: Select all
package main
import "fmt"
func main() {
slice := []int{1, 2, 3}
if cap(slice) == len(slice) {
newSlice := append(slice, 4)
fmt.Println(newSlice)
} else {
newSlice := append(slice, 4)
fmt.Println(newSlice)
}
}