Комментарии 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