Pull to refresh

Comments 12

В оперативной памяти же массивы выглядят просто как последовательность значений одного размера. Они занимают фиксированный объем и имеют постоянное расположение в памяти на всё время жизни, пока за ними не придет сборщик мусора.

Это не совсем так, расположение в памяти может меняться потому что есть механизм 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. Спасибо большое за этот пример, если не возражаете добавлю его в статью с упоминанием вас.

Все верно. Конечно не возвражаю.

Два действия с b[1] являются отвлекающим маневром)

Вчера так же показал своим коллегам, им понравилось и немного попались на уловку с append. "Немного", так как были сомнения)

Можно поинтересоваться, зачем в языке с GC эта машинерия?


Где почитать про неэффективность коллекций например в JDK и .NET, толкнувшую голанг выставить наружу именно вот эти кишки?

GC тут в целом не причём, в первую очередь думаю это связано с попытками сделать более эффективное использование/переиспользование памяти.
Я тоже пытался найти что-то на тему мотивации. Но подозреваю, что такое решение было принято внутри команды.

И зачем нужны массивы, если можно просто всегда использовать срезы?

Может массивы размещаются в стеке? Это было бы логично, раз мы знаем их размеры на этапе компиляции, то почему бы и нет, но подтверждений этому я не нашёл. Везде пишут: "Ну мы сделали, а там смотрите сами, если удобно, то вот"

С размещением там не так всё просто. Массивы могут размещаться на стеке, а срезы только на стеке и живут (но в срезах нет значений, они просто ссылки на массивы). Но при этом массивы могут убегать в кучу, если в них слишком много элементов.

Где-то в спецификации Go найти про это я не смог. Поисследовать поведение можно командой go build -gcflags="-m", она выводит информацию о том, кто уходит в кучу со стека.

Немного подробнее это объясняется в этой статье на медиуме.

Очень интересно. Получается, что массивы до 64КБ живут в стеке и передаются по ссылке, а более крупные живут в куче и передаются по значению, при том, что это массивы, не слайсы. Тёмные закоулки Гошки)

Вот, вы пишете:

// создаем некоторый массив и срез от него  
a := []int{1, 2}  
s := a[:]  

Но ведь a -- это не массив, а срез. Фактически, тут у вас 2 среза, ссылающихся на один массив. Вы или многоточие в квадратные скобки добавьте, или тоже срезом назовите.

Действительно) Большое спасибо)

Only those users with full accounts are able to leave comments. Log in, please.