Comments 14
В оперативной памяти же массивы выглядят просто как последовательность значений одного размера. Они занимают фиксированный объем и имеют постоянное расположение в памяти на всё время жизни, пока за ними не придет сборщик мусора.
Это не совсем так, расположение в памяти может меняться потому что есть механизм stack grow. В случае алокации в куче на практике фиксированно (потому что гц не мувит в настоящий момент), но GO не дает гарантий что адрес не может поменяться.
Вопрос на засыпку. Так сказать закрепим материал)
Что выведет данный код?
a := [...]int{1,2,3,4,5,6}
b := a[2:5]
b[1] = 7
b = append(b, 8)
b[1] = 9
fmt.Printf(`%v`, a)Оба раза b[1] изменит значение в массиве a, из-за того что len не выходит за границы cap. Но тут на самом деле даже интересней, потому что append перезапишет последний элемент массива a. Это связано с тем, что срез b создаётся со значением cap умещающимся в выделенную память для массива a. То есть другим языком если например взять срез a[:2] его значением cap в данном примере будет 6, несмотря на то, что len будет 2. И все append будут перезаписывать элементы исходного массива, пока len не выйдет за границы cap. Спасибо большое за этот пример, если не возражаете добавлю его в статью с упоминанием вас.
Можно поинтересоваться, зачем в языке с GC эта машинерия?
Где почитать про неэффективность коллекций например в JDK и .NET, толкнувшую голанг выставить наружу именно вот эти кишки?
И зачем нужны массивы, если можно просто всегда использовать срезы?
Может массивы размещаются в стеке? Это было бы логично, раз мы знаем их размеры на этапе компиляции, то почему бы и нет, но подтверждений этому я не нашёл. Везде пишут: "Ну мы сделали, а там смотрите сами, если удобно, то вот"
С размещением там не так всё просто. Массивы могут размещаться на стеке, а срезы только на стеке и живут (но в срезах нет значений, они просто ссылки на массивы). Но при этом массивы могут убегать в кучу, если в них слишком много элементов.
Где-то в спецификации Go найти про это я не смог. Поисследовать поведение можно командой go build -gcflags="-m", она выводит информацию о том, кто уходит в кучу со стека.
Немного подробнее это объясняется в этой статье на медиуме.
Вот, вы пишете:
// создаем некоторый массив и срез от него
a := []int{1, 2}
s := a[:] Но ведь a -- это не массив, а срез. Фактически, тут у вас 2 среза, ссылающихся на один массив. Вы или многоточие в квадратные скобки добавьте, или тоже срезом назовите.
Интересно, что большинство ресурсов которые я читал наоборот рекомендуют использовать только слайсы)
Нарезаем массивы правильно в Go