copy и правка на месте
Аня оставила на ревью импорта комментарий: зачем плодить лишние копии, если можно править данные на месте. Миша переписал фильтрацию на правку по месту, и Аня приняла правку с первого раза.
copy — прямой и самый явный способ получить независимую копию данных слайса; а срез nums[:0] с append позволяет менять слайс на месте, без аллокаций.
Copy
Что здесь показано
- Стек — локальные переменные функции.
i = 3— значение;p = ptr → 10— указатель на значение;b = "hello"— срез (заголовок: указатель + длина + ёмкость). - Куча — данные, на которые ссылаются переменные:
rodata— байты строки-литерала (в бинарнике),данные N Б— бэкинг-массив слайса,строка— динамическая строка. - Горутины — лёгкие потоки Go: статус (running/runnable/waiting…), функция, в которой каждая сейчас находится, размер стека (растёт по мере работы) и пометка «из main» — горутина запущена из твоего кода.
- GC — сборщик мусора: фаза (off/mark) и число завершённых циклов.
copy копирует элементы и возвращает количество скопированных — минимум из длин источника и приёмника. Присваивание копирует только заголовок, а copy — сами данные. Если нужно «отвязать» слайс от исходного массива, копируй в новый слайс.
Фильтрация на месте
Классика — отобрать элементы, не выделяя новую память:
func filterInPlace(nums []int, keep func(int) bool) []int {
out := nums[:0]
for _, n := range nums {
if keep(n) {
out = append(out, n)
}
}
return out
}
nums[:0] — тот же массив, но с длиной ноль. append дописывает отобранные элементы поверх исходных, а лишние в конце отбрасываются изменением длины. Функция переиспользует память исходного слайса и не аллоцирует ничего нового.
Range копирует заголовок
range по слайсу копирует только заголовок, поэтому изменения элементов в теле цикла видны сразу. Переменная v внутри range — копия элемента, писать в неё бесполезно:
for i, v := range s {
v = v * 2 // меняет копию, не слайс
s[i] = s[i] * 2 // меняет слайс
}
Вы узнаете:
- как удалить элемент из слайса
- чем
slices.Clone(s)отличается отcopy - как сравнить производительность
copyи ручного цикла
Проверьте себя
При импорте записи перекладывают между буферами разной длины: dst := make([]int, 4); n := copy(dst, []int{1, 2, 3}). Чему равно n?
Чем copy(dst, src) отличается от простого присваивания dst := src?
В цикле for i, v := range s запись v = v * 2: что произойдёт?
правильных ответов
copy — независимая копия; nums[:0] + append — правка на месте без аллокаций; в range переменная — копия элемента.
10 000 ₽ · 60 минут · онлайн