Pull to refresh

Comments 14

"Все мозги разбил на части, все извилины заплёл, И канатчиковы власти колят нам второй укол "

Чем отличается "мы переприсваивали значение переменной " от "мы просто передаем саму переменную (не ссылку, а именно переменную!) " ?

Надо как то этот важный и тонкий момент попонятнее описывать. Что б вот прям различие очевидно было!

(Можно даже в картинках..)

:-)

Срез слайса это конечно круто (интересно как на английском:) ).

А вообще конечно лихо они объединили владеющую и невладеющую структуры данных, это наверное стало возможно из-за того что язык со сборкой мусора?

В голанге нет концепции владения, так что не надо пытаться приложить концепции из крестов - это только сделает вам больнее :)

Интересная тема с удвоением размера. Получается на очень толстых и плавно растущих массивах можно получить почти половинную потерю памяти под резерв.

И тогда надо писать свои кастомные append`ы, которые это дело нивелируют.

Такая особенность у аппендров есть, да. Тут банальный вопрос: известна ли вам заранее длина слайса? Если да, то будем выделять памяти столько, сколько нужно.

Если же нет, то вам нужно выбрать стратегию, по которой память под массив будет переаллоцироваться. Разработчики Go выбрали вариант увеличения памяти в 2 раза (редко не в 2). В большинстве случаев такая стратегия эффективна.
Аллоцировать память для каждого нового элемента большого слайса выглядит сомнительным вариантом, поэтому не очень понятно, о каком "кастомном append'е" идет речь

Ну например есть у меня много массивов элементов, но всегда в каждом будет не больше 1.2 млн штук. И я это выяснил на профилировании. При этом далеко не все из них и до миллиона доходят. Те что выйдут за миллион, будут жрать на 2 млн элементов и большая часть памяти будет в простое.

Нет, слайс увеличивается не всегда в 2 раза. Автор забыл упомянуть изменения в go 1.14 и 1.20 (и в 1.21 вроде как планируются еще изменения по оптимизации).

Формула роста такова:

starting cap    growth factor 
256             2.0 
512             1.63 
1024            1.44 
2048            1.35 
4096            1.30

Следить за ней можно вот тут в исходниках: go/src/runtime/slice.go

https://go.googlesource.com/go/+/2dda92ff6f9f07eeb110ecbf0fc2d7a0ddd27f9d вот тут изменения

Я правильно понимаю, что, при передаче слайса в функцию в качестве параметра, нет необходимости передавать его по ссылке? Можно передать его по значению и, в итоге, будет создан новый слайс, который, однако, ссылается на массив исходного слайса. Т.е., в таком случае, мы не будем копировать значения и расходовать на это память?

на эту тему тут на хабре есть хорошая статейка - https://habr.com/ru/articles/525940/

если коротко - зависит от ситуации и от того что будет делать функция в которую передается этот слайс.

Только читать, например. Статейку почитаю, спасибо. Похоже, это прямо то, что мне нужно для повышения образованности.

Да, append - штука забавная.

package main

import "fmt"

func main() {
	t1 := make([]int, 0, 5)
	t1 = append(t1, 1)
	_ = append(t1, 2)
	t2 := append(t1, 3)
	fmt.Println(t1, t2)

	t3 := t2
	t3[0] = -1
	fmt.Println(t1, t2, t3)

	t3 = append(t3, 4)
	fmt.Println(t1, t2, t3)
}

https://go.dev/play/p/cV9tCbSY5cF

Можете пояснить следующий момент?:

Переменная, которую мы инициализировали со значением массива, содержит именно значения массива, а не ссылку на первый элемент массива (как это сделано в C).

Массив находится в памяти начиная с какого-то адреса. Как может переменная содержать значение массива, а не ссылку на массив? Значения могут быть только в регистрах процессора. Если значение переменной хранится в стеке, то мы обращаемся к ней через указатель на стек+смещение. Если значение хранится в "куче", то обращаемся просто через указатель.

Мне как начинающему разработчику на Go, информация очень полезна.

Погружение в глубины языка дается не очень легко, так что благодаря таким статьям становлюсь чуть лучше. Спасибо автору

В сатье куча фактических ошибок!

Sign up to leave a comment.

Articles