GoLang Slice в деталях, простым языком — Transcript

Подробное объяснение устройства слайсов в Go, их связи с массивами и работы функции append простым языком.

Key Takeaways

  • Понимание внутренней структуры слайсов критично для эффективного программирования на Go.
  • Слайсы используют базовый массив, что позволяет эффективно управлять памятью.
  • Функция append изменяет длину слайса и может перезаписывать элементы базового массива.
  • Массивы в Go имеют фиксированную длину и используются для специфических задач.
  • Знание работы слайсов важно для успешного прохождения технических собеседований.

Summary

  • Слайс в Go — это динамическая последовательность элементов, связанная с базовым массивом.
  • Важность понимания внутреннего устройства слайсов для написания качественного кода и успешных собеседований.
  • Слайсы состоят из трех элементов: указатель на базовый массив, длина и емкость.
  • Разница между длиной и емкостью слайса и их влияние на работу с данными.
  • Связь с массивами: массивы имеют фиксированную длину, слайсы — динамическую.
  • Пример использования массивов для хранения фиксированных данных, например UID.
  • Функция append добавляет элементы в слайс, увеличивая его длину и перезаписывая элементы базового массива.
  • Возможность создания нескольких слайсов на одном базовом массиве с разной длиной и емкостью.
  • Практическая реализация функции append для закрепления теории.
  • Объяснение, что слайс и срез — это одно и то же понятие в Go.

Full Transcript — Download SRT & Markdown

00:00
Speaker A
В этом видео мы разберем слайсы в языках буквально на кусочки, и я постараюсь максимально простым и понятным языком рассказать вам, как они устроены по своей сути. Слайс — это просто тип данных, а именно последовательность с динамической длиной. Ближайшая аналогия из других языков программирования — например, динамические массивы или списки в других языках. Обычно принято опускать то, как они устроены внутри, но в Go, к сожалению, или частью так поступить не получится. В Go крайне важно понимать, как устроен слайс, и без этого понимания вы полностью не сможете писать хороший код и будете регулярно стрелять себе в ногу. К тому же слайсы очень любят на собеседованиях, и там без них вам уж точно не обойтись. Слайсы имеют очень простую структуру, и разобраться в них очень просто. Буквально к концу этого видео вы будете знать о них практически все. И, пожалуй, я заранее сделаю парочку оговорок. Во-первых, слайс на русский язык обычно переводят как срез, и в ходе своего повествования я периодически могу употреблять эти слова. То есть имейте в виду, что когда я говорю слайс или срез, я на самом деле имею в виду одно и то же. И последняя оговорка: здесь мы не будем рассматривать в подробностях синтаксис слайсов. Я уверен, что в этом вы прекрасно разберетесь и без меня, а здесь мы поговорим о их внутреннем устройстве и различных нюансах. Что ж, давайте теперь разберем план действия. Так уж вышло, что понятие слайса неразрывно связано с понятием массива, и без их четкого понимания мы не сможем двигаться дальше. Поэтому начнем мы именно с массивов. Но устроены они намного проще, чем сами слайсы, и поэтому здесь мы надолго задерживаться не будем. Далее, как я и обещал, мы разберем слайсы на винтики и в подробностях посмотрим, как они устроены внутри. Далее мы перейдем к функции append и в деталях разберемся, как происходит добавление элементов в слайс. И когда мы наконец будем понимать, как всё это работает, мы разберем различные полезные практики, а также подводные камни и опасности, которые у вас могут подстерегать при работе со слайсами. И я считаю, что когда мы изучаем что-то новое, очень полезно попробовать написать это своими руками. Поэтому для закрепления теоретической части мы напишем простенькую реализацию функции append. Ну что же, давайте начинать. Массив представляет из себя последовательность с фиксированной длиной и состоит из одного типа. Записывается он следующим образом: мы всегда обязательно указываем размер массива, и число элементов, и собственно значение этих элементов. И фиксированного размера массив редко используется в Go непосредственно, но в некоторых случаях они могут оказаться довольно удобны. Например, их очень удобно использовать для хранения каких-то последовательностей фиксированной длины. Примером такой последовательности может быть UID. Скорее всего, вы с ним уже знакомы, а если нет, то советую почитать в интернете. Мы всегда точно знаем размер UID — это 16 байт или 128 бит, и никогда из него ничего не удаляем и не добавляем. Поэтому массивы здесь выгодны и в плане производительности кода, и в плане его читаемости. То есть когда мы в коде видим массив, мы лучше понимаем, что с ним будет происходить далее, потому что круг возможных действий гораздо меньше, чем, например, со слайсами. В общем-то, это всё, что вам необходимо знать об устройстве массивов. И если они в Go используются редко, то со слайсами вы будете работать практически каждый день. Давайте теперь посмотрим и на их внутреннее устройство. Записываются они практически в точности так же, как и массивы, но с небольшими изменениями. Мы не указываем размер, что в общем-то логично, ведь мы уже говорили, что размер слайса не фиксирован, то есть он может меняться по ходу работы программы. И естественно, мы не можем его зафиксировать. Всё, что мы можем сделать, — это разве что аллоцировать память заранее, когда мы создаем этот слайс. Что такое аллокация памяти и зачем нам это нужно в случае слайса, мы посмотрим чуть позже, а пока давайте посмотрим на их внутреннее устройство. По сути, слайс — это некая структура, которая состоит из трех элементов. Первый и наиболее важный элемент — это ссылка на некий базовый массив. Именно здесь проявляется тесная связь слайса и массива. На самом деле элементы последовательности не хранятся непосредственно в слайсе, они находятся в этом самом базовом массиве, и слайс имеет только ссылку на него. Но слайс не обязательно использует этот массив целиком. Во-первых, эта ссылка указывает не просто на массив, а на первый элемент массива, который используется в слайсе. А вот последний используемый элемент определяется с помощью следующего параметра — это длина. Как видно из названия, это количество элементов, которые фактически используются в слайсе. И последний параметр — это capacity, или же емкость. Если говорить простым языком, то это количество элементов, которые влезают в базовый массив. Но естественно, с учетом того, что первый элемент слайса не обязательно совпадает с первым элементом массива. То есть, к примеру, если размер массива — это 10, но мы его используем, начиная с пятого элемента, то естественно туда влезет только пять элементов. То есть capacity в этом случае будет 5. Если вы сейчас мало что поняли, то это абсолютно нормально. Сейчас мы посмотрим на устройство слайса более наглядно, и всё станет понятнее. Допустим, у нас есть некий базовый массив, который выглядит следующим образом: у него есть имя, в его ячейках есть какие-то значения, и у них есть свои номера, то есть индексы. Допустим, мы хотим создать на его основе слайс и решили использовать ячейки с 4 по 7. Это будет выглядеть следующим образом. Во-первых, размер такого слайса будет равен трем, поскольку у нас используются ячейки с номерами 4, 5 и 6. Несмотря на то, что в нашей записи также указано число 7, эта ячейка не используется, потому что правая граница указывается не включительно. Далее мы видим, что емкость такого слайса будет равна 9, и на схеме это наглядно видно. То есть массив вмещает 9 элементов. Ну естественно, указатель у нас смотрит на элемент с номером 4, поскольку именно его мы определили как первый элемент слайса. А далее, на самом деле, массив может быть использован не только для одного слайса, а для любого их количества. К примеру, на этом же массиве мы можем определить второй слайс. Допустим, в нем будут находиться элементы с 6 по 9. В таком случае, как вы видели, его длина также будет равна трем, но емкость уже будет отличаться, поскольку мы начинаем с другого элемента, и в оставшуюся часть массива влезает уже не 9, а всего 7 элементов. Это также наглядно видно на схеме. А теперь давайте поговорим про добавление в слайс элементов. Для этого в Go уже есть встроенная функция, которая называется append. Но, как мы увидим чуть позже, можно написать даже собственную ее реализацию, и это не так уж сложно. Для того чтобы наглядно продемонстрировать работу этой функции, давайте возьмем вот такой вот простой слайс, в основе которого лежит базовый массив из шести элементов. Длина слайса равна трем, а емкость — 6, то есть нам еще есть куда расти. В данный момент слайс у нас выглядит следующим образом. Так-то вы могли заметить, что в элементах с номерами 3, 4 и 5 также есть какие-то значения. Они никак не относятся к текущему слайсу, а относятся только к базовому массиву. Таким образом, я хотел подчеркнуть тот факт, что в базовом массиве не всегда должны содержаться нулевые значения. И добавление в слайс на самом деле не добавляет какие-то новые элементы, а перезаписывает предыдущие. Сейчас мы все это наглядно увидим. Допустим, мы хотим добавить в слайс вот такой элемент. Что произойдет после вызова функции append? Первое, что мы естественным образом ожидаем, — это появление данного элемента в нашем слайсе. С точки зрения высокоуровневого использования слайса, именно это и произойдет. Но что же произойдет внутри? Во-первых, на единичку увеличится длина слайса, и во-вторых, последний элемент слайса с учетом его новой длины будет перезаписан, и в нем будет содержаться то значение, которое мы хотели добавить в слайс. И дальше, когда мы захотим добавлять новые элементы, будет происходить ровно то же самое. То есть, к примеру, мы вызвали append ещё раз.
00:14
Speaker A
языков программирования например динамические массивы или списке в других языках обычно принято опускать то как они устроены внутри но в go к сожалению или частью так поступить не получится в go крайне важно понимать как устроен слайс и без этого понимания вы полностью
00:30
Speaker A
не сможете писать хороший код и будете регулярно стреляет себе в ногу к тому же слайсы очень любят на собеседованиях и там без них вам уж точно не обойтись частью слайсы имеет очень простую структуру и разобраться в них очень
00:42
Speaker A
просто буквально к концу этого видео вы будете знать о них практически все и пожалуй я заранее сделаю парочку оговорок во-первых слайс на русский язык обычно переводят как срез и в ходе своего повествования я периодически могут утолить словах то есть имейте
00:57
Speaker A
ввиду что когда я говорю слайс или стресс я на самом деле имею в виду одно и то же и последняя здесь мы не будем рассматривать в подробностях синтаксис слайс of я уверен что в этом было прекрасно разберетесь и без меня а здесь
01:09
Speaker A
мы поговорим о их внутреннем устройстве и различных нюансах что ж давайте теперь разберем план действия так уж вышло что понятия слоится неразрывно связано с понятием массива и без их четкого понимания мы не сможем двигаться дальше поэтому начнем мы именно с массивов но
01:25
Speaker A
устроены они намного проще чем сами слайсы и поэтому здесь мы надолго задерживаться не будем далее как я и обещал мы разберем слайсы на винтики и в подробностях посмотрим как они устроены внутри далее мы перейдем функции append и в деталях разберемся как происходит
01:41
Speaker A
добавление элементов слайс и когда мы наконец будем понимать как всё это работает мы разберем различные полезные практики а также подводные камни и опасности которые у вас могут подстерегать при работе со слайсами и я считаю что когда мы изучаем что-то новое
01:56
Speaker A
очень полезно попробовать написать это своими руками поэтому для закрепления теоретической части мы напишем простенькую реализацию функции append ну что же давайте начинать мысе представляет из себя последовать с фиксированной длины и состоит если одного типа записывается он следующим образом мы всегда обязательно указываем
02:17
Speaker A
размер массива и пиво элементов и собственно значение этих элементов и за фиксированного размера массива редко используется в go непосредственно но в некоторых случаях они могут оказаться довольно удобно и например их очень удобно использовать для хранения каких-то последовательностей и
02:32
Speaker A
фиксированной длины примером такой последовательности может быть uid скорее всего вы с ним уже знакомы а если нет то советую почитать в интернете мы всегда точно знаем размер у эда это 16 байт или 128 бит и никогда из него ничего не
02:46
Speaker A
удаляем и не добавляем поэтому массивы здесь выгодны и в плане производительности кода и в плане его читаемости то есть когда мы в ходе видим массив мы лучше понимаем что с ним будет происходить далее потому что круг возможных действий гораздо меньше чем
03:00
Speaker A
например слайсами в общем то это все что вам необходимо знать об устройстве в массивах и если они в go используются редко то сослать мы вы будете работать практически каждый день давайте теперь посмотрим и на их внутреннее устройство записываются они практически в точности
03:16
Speaker A
так же как и массивы но с небольшим изменениям мы не указываем размер что в общем-то логично ведь мы уже говорили что размер слайс а не фиксирован то есть он может меняться по ходу работы программы и естественно мы не можем
03:28
Speaker A
мозга то есть он может меняться по ходу работы программы и мы никак не можем его зафиксировать все что мы можем сделать это разве что аллоцировать память заранее когда мы создаем этот слайд что такое аллокация памяти и зачем нам нужно
03:40
Speaker A
в случае с лайсом мы посмотрим чуть позже а пока давайте посмотрим на их внутреннее устройство по сути слайс это некая структура которая состоит из трех элементов первый и наиболее важный элемент это ссылка на некий базовый массив именно здесь проявляется тесная
03:55
Speaker A
связь с лайсом и массивов на самом деле элементы последовательности не хранятся непосредственно в слайсы они находятся в этом самом базовом массиве и слайд имеет только ссылку на него но слазь не обязательно используют этот массив целиком во первых эта ссылка указывает
04:10
Speaker A
не просто на массив а на первый элемент массива которая используется в слайсы а вот последний используемый элемент определяется с помощью следующего параметра это длина как видно из названия это количество элементов которые фактически используются в слайсер и последний параметр это
04:26
Speaker A
capacity или же емкость если говорить простым языком то это количество элементов которые влезает в базовый массив но естественно с учетом того что первый элемент слайс а не обязательно совпадает с первым элементом массива то есть примеру если размер массива это 10
04:42
Speaker A
но мы его используй начиная с пятого элемента то естественно туда влезет только пять элементов то есть capacity в этом случае будет 5 если вы сейчас мало что поняли то это абсолютно нормально сейчас мы посмотрим на устройство насладиться более наглядно и все станет
04:57
Speaker A
понятнее допустим у нас есть некий базовый массив который выглядит следующим образом у него есть имя в его ячейках есть какие-то значения и у них есть свои номера то есть индексы допустим мы хотим создать на его основе слайсы и решили использовать и чехи с 4
05:12
Speaker A
по седьмую это будет выглядеть следующим образом во-первых размер такого слоя будет равен трем поскольку у нас используются ячейки с номерами 4 5 и 6 несмотря на то что в нашей записи и также указано число 7 эта ячейка не
05:25
Speaker A
используется потому что правая граница указывается не включительно далее мы видим что емкость такого слоя будет равна 9 и на схеме это наглядно видно то есть массив влезает 9 элементов ну естественно указатель у нас смотрит на элемент с номером 4 поскольку именно его
05:40
Speaker A
мы определили как первый элемент слайс а далее о самом деле массив может быть использован не только для одного слайс а а для любого их количество к примеру на этом же массиве мы можем определить или 2 слайс допустим в нем будут находиться
05:54
Speaker A
элемент то 6 по 9 в таком случае как вы видели его длина также будет равна трем но емкость уже будет отличаться поскольку мы начинаем с другого элемента и в оставшуюся часть массива влезает уже не 9а всего 7 элементов это также
06:08
Speaker A
наглядно видно на схеме а теперь давайте поговорим про добавление в слайс элементов для этого в go уже есть встроенная функция которая называется append но как мы увидим чуть позже можно написать даже собственную ее реализацию и это не так уж сложно для того чтобы
06:23
Speaker A
наглядно продемонстрировать работу этой функции давайте возьмем вот такой вот просим dislike в основе которого лежит базовым сеть из шести элементов длина слазь равна трем а емкость 6 то есть нам еще есть куда расти в данный момент слайс у нас выглядит следующим образом
06:37
Speaker A
так-то вы могли заметить что в элементах с номерами 3 4 и 5 также есть где-то значения они никак не относятся к текущему слайс у относятся только к базовому массиву таким образом я хотел подчеркнуть тот факт что в базовом
06:49
Speaker A
массиве не всегда должны содержаться нулевые значения и добавление в слайд на самом деле не добавляли какие-то новые элементы а перед записывают предыдущие сейчас мы все это наглядно увидим допустим мы хотим добавить слайд вот такой элемент что произойдет после
07:04
Speaker A
вызова функции append первое что мы естественным образом ожидаем это появление данного элемента в нашем слайсер с точки зрения высокоуровневое использования слайс а именно это и произойдет но что же произойдет внутри во первых на единичку увеличится для нас лайса и во-вторых последний элемент
07:21
Speaker A
слайс с учетом его новой длины будет перезаписан и в нем будет содержаться то значение которое мы хотели добавить в слайс и дальше когда мы захотим добавлять новые элементы будет происходить ровно то же самое то есть примеру мы вызвали append ещё раз и у
07:35
Speaker A
нас снова увеличилась длина слайс а на единичку и последний элемент также будет перезаписан вызываем append еще раз и видим все тоже самое и вот здесь мы подобрались к самому интересному моменту мы видим что длина емкость слоя совпадают это означает что в базовый
07:51
Speaker A
массив больше не влетит ни одного элемента но при этом нас никто не ограничивает в их добавление что же произойдет после очередного вызова append конечно же элемент будет добавлен слайд но как это произойдет на схеме мы сейчас видим что емкость стало меньше
08:04
Speaker A
чем длина и такого быть конечно же никак не может на самом же деле произойдет следующее во-первых будет создан новый базовый массив и большинстве случаев его размер будет в два раза больше чем у предыдущего далее все элементы старого массива которые входят в наш слайд будут
08:20
Speaker A
скопированы в новый и в итоге мы получаем набор ячеек в которые перспективе могут быть записаны новые значения ну и последним этапом конечно же нашим слайсы будет изменена ссылка которая указывает на базовый массив теперь она будет указывать на новый
08:33
Speaker A
массив а то что произойдет созданы мм и силам нас уже не волнует возможно он по каким-то причинам продолжить свое существование может быть просто будет собран году бишь коннектором что уж теперь нам известны практически все основные моменты которые нужно знать про слайс остались еще какие
08:47
Speaker A
мелочи но у моих разберем время разговора про различные полезные практики и подводные камни и займемся мы этим прямо сейчас для того чтобы вы смогли понять и осознать первый совет нужно разобраться с нулевым значением слайсы для этого давайте перейдем к коду
09:02
Speaker A
и немножко с ним поиграемся во-первых нулевое значение слайсы равно нил создаем слоях с именем лист и выведем на экран результат сравнения с нею запускаем и смотрим и да действительно видим что результат равен true но давайте посмотрим еще вот на такой
09:18
Speaker A
случай мы снова возьмём нашу переменную лист и присвоим ей значение пустого слайсы и аналогичным образом выведем результаты сравнения снегу и мы видим что во втором случае результат сравнения будет falls почему же так происходит и в чем разница в первом случае мы и создали переменную
09:36
Speaker A
лист типа слайс но не положили в нее никакого значения а во втором случае мы уже про инициализировать переменную пусть и пустым слай сам то есть какое-то значение у нее уже есть но у этого слайс а нет элементов и именно здесь нас
09:50
Speaker A
подстерегает первая опасность потому что у некоторых разработчиков есть соблазн проявлять слайд на пустоту сравнивая его с нею но как мы только что убедились это не всегда сработает и в общем случае лучше делать такие проверки с помощью функции лен то есть напрямую проверяет
10:05
Speaker A
длину слайсы выглядеть это будет следующим образом убираем лишнее проверки запускаем код и проверяем результат здесь мы видим что в обоих случаях мы получили именно то что ожидали увидеть и на самом деле когда вы работаете со сластями вас абсолютно и должно
10:25
Speaker A
волновать с чем вы имеете дело с нулевым с лайсом ядер со слаксом с 0 длиной все функции которые работают со слайсами должны корректно и полноценно работать также есть милыми слайсами к примеру вы без проблем можете применить такому слайс у функцию append и она должна
10:40
Speaker A
корректно отработать давайте попробуем это сделать запускаем и проверяем да мы видим что несмотря на то что слайд был изначально 0 функция append корректно отработало и добавила в него значение подытоживая все вышесказанное получаем первый совет он заключается в том что проверять слайс на
11:01
Speaker A
пустоту лучше с помощью функции лин они сравнивая его например snell двигаемся дальше и возвращаемся к коду теперь мы поговорим про локацию памяти под слайс когда мы создаем слайс мы можем заранее определить какая у него будет длина и емкость для этого можно воспользоваться
11:17
Speaker A
функцией мейк на вход она ожидает три аргумента первый это тип слайсы который мы хотим создать следующий аргумент это длина этого слоя и последний аргумент это его емкость давайте присвоим это какой-нибудь переменной например 100 же лист и посмотрим что получилось
11:34
Speaker A
во первых выведем его длину а во-вторых емкость запускаем и смотрим чему они равны и видим что его длина емкость равны тем значением которые мы указали функции майк для чего это может понадобиться давайте представим что у нас есть вот такой вот слайд в котором
11:51
Speaker A
содержатся различные числа и допустим перед нами стоит задача получить слазь в котором будут храниться все эти значения но только удвоенные то есть мы ожидаем получить вот такие значения для этого давайте напишем функцию дабл которая на вход будет принимать слайс из интерьеров и
12:09
Speaker A
возвращать она будет также слайс далее мы создаем переменную с которой будет находиться результат и теперь нам просто нужно прибрать все значения и умножить каждое из чисел на два после умножения каждый элемент должен быть добавлен результирующий слайс то есть выглядеть это будет следующим
12:27
Speaker A
образом и в конце мы просто возвращаем результат давайте запустим эту функцию и проверим sony работает правильно да все работает корректно мы получили то что ожидали но что же с этой функции не так на самом деле она работает не
12:45
Speaker A
оптимально изначально слайд в котором мы будем хранить результат у нас 0 то есть у него нет никого базово массива и когда мы первый раз него что-то кладём этот базовый массив создается допустим его длина равняется единице когда мы кладем
12:59
Speaker A
у него второй элемент то естественно мы не влезаем в емкость из этого массив или создается и доп теперь его длина равняется двум то есть удвоенный предыдущий когда мы пытаемся положить что-то в третий раз там и снова не влезаем и теперь мы создаем массив
13:15
Speaker A
длиной в 4 элемента двигаемся дальше следующая итерация кладет в него четвертый элемент и теперь мы вполне влезаем то есть размер массива 4 соответственно емкость слайс а также 4 и у нас все прекрасно врезается но когда мы перейдем к пятому элементу мы снова у
13:31
Speaker A
ты каемся в размер массива и нам снова нужно его пересоздавать и на этот раз его длина будет 8 итого мы получаем что пройдя всего лишь 5 итерации мы четыре раза создаем новый массив и каждый раз к первым блюдам элементы из предыдущего и
13:45
Speaker A
мы могли бы этого избежать если бы мы проинициализировать изначально переменную рис с помощью функции мейк сделать это можно двумя способами которые друг на друга очень похоже 1 будет выглядеть вот таким образом то есть у нас будет создан слайс у
14:01
Speaker A
которого емкость равна размеру предыдущего слайсы таким образом размер результирующего славится будет изначально правильным и нам ни разу не придется его при создавать и второй способ выглядит следующим образом вместо емкости мы можем указать размер результирующего слайс а но тогда нам
14:18
Speaker A
придется немножко подправить код внутри цикла потому что такое слайс уже будет хранить в себе элементы у которой будет нулевое значение то есть нам не нужно ничего добавлять и на числа из просто станет два раза больше во первых здесь
14:30
Speaker A
нам понадобится индексы элементов и вместо вызова функции append мы присваиваем новое значение этому элементу слайсер проверяем на всякий случай не сломали ему работу функции и видим что она все еще работает корректно и какой из этих вариантов использовать вы можете выбрать
14:48
Speaker A
самостоятельно сколько оба они работают вполне корректно лично мне больше нравится первый вариант потому что он проще для понимания мы просто естественным образом используя функцию append имени делаем ничего сложного что же в итоге мы получаем следующий совет если вам
15:03
Speaker A
известен размер итогового слайс а то всегда лоцируется под него память таким образом вы избегаете бессмысленного копирование элементов из одного массива в другой теперь давайте обсудим придачу слайс а по значению и по ссылке во-первых в том но предавать слайс по
15:19
Speaker A
значению нет никаких проблем на первый взгляд это может показаться плохой идеей потому что в слайде потенциально может хранится множество элементов и мы не хотим все их копировать при передачу другую функцию но я напомню что сам слазь не содержит в себе все эти
15:33
Speaker A
значения в нем хранится лишь ссылка на первый элемент массива и когда мы передаем слайс по значению мы копируем всего три параметра это размер емкость и ссылка на базовый массив но на самом деле здесь спрятаны кое-какие другие опасности давайте я вам их
15:49
Speaker A
продемонстрирую во-первых создаем какой-нибудь слазь пусть в нем лежит четыре элемента создадим функцию в котором будем его передавать обращаю внимание что здесь я передаю слайс именно по значению они посылки давайте попробуем изменить один из элементов полученного слайсы и функции main мы сначала выведем исходный
16:11
Speaker A
слайс далее вызовем функцию и выведем слайд еще раз чтобы проверить что у нас поменялось здесь я предлагаю поставить видео на паузу и подумать самостоятельно какой результат мы сейчас получим и почему он получится именно таким и мы видим что функция действительно
16:32
Speaker A
поменяло значение одного из элементов и это произошло даже несмотря на то что мы передавались life по значению здесь конечно же дело в том что в слайсы хранится не значение базового массива а ссылка на него то есть вне зависимости
16:45
Speaker A
от того каким способом мы придаем слайс базовый массив всегда будет передан по ссылке теперь давайте эту строчку закомментируем и попробуем сделать следующее мы добавим в наш слайд какой-нибудь элемент с помощью функции append и также добавим прямо в этой функции еще
17:01
Speaker A
одну строчку с выводом и чтобы не запутаться давайте добавим вывод подсказки запускаем и смотрим результат естественно у нас ничего не поменялось потому что мы смотрим исходный слайс а не то что возвращает функция append но что если мы будем передавать функцию
17:22
Speaker A
append не весь наш слайд а только небольшой его кусочек то есть мы можем взять от нашего исходного слоя со еще один но чуть-чуть поменьше и довга можно делать слазь и только от массива но и от рук о вас лайса делать это точно таким
17:35
Speaker A
же образом в том месте где мы вызываем хендл и придаем туда лист мы допишем вот такой кусочек то есть теперь мы передаем слайд который состоит только из одного элемента и перед тем как запустить код давайте функцию findall будем выводить
17:48
Speaker A
не исходный список а то что вернуло функция append так будет немного интереснее запускаем и смотрим что получилось во первых здесь мы видим что внутри функции хинду элемент действительно добавился то есть поливали мы один элемент и теперь у нас
18:04
Speaker A
их два но гораздо более интересна ситуация произошла снаружи мы видим что во внешних слоях ничего не добавилось но при этом у нас почему-то поменялся второй элемент давайте разберемся почему так произошло во первых когда мы берем слайс от другого слайсы у них обоих
18:19
Speaker A
остается общей базовый массив но при этом у них может отличаться емкость длина это какой элемент из этого базового массива будет первым в нашем случае первый элемент остается прежним но длина слайсер становится меньше то есть в нашем функцию приходит вот такой
18:36
Speaker A
вот слайс во первых его основе лежит базовый мастиф состоящий из четырех чисел но его длина равна единице и таким образом используется только один элемент этого массива это единичка а теперь вспоминаем что происходит при вызове функции append во-первых длина слайс а увеличивается на
18:55
Speaker A
единичку и таким образом у нас увеличивается используемая часть массива то есть теперь у нас два элемента и последним шагом последний используемый элемент массива заменяется на то значение которое мы хотим добавить слайс то есть здесь мы хотим добавить пятерку
19:10
Speaker A
и значит последний элемент заменяется на пятерку и именно такое значение мы и увидели выводе наших программ и то здесь 1534 и здесь также видим 1534 и также я обращаю ваше внимание на то что длина и емкость внешнего слоя со не изменились
19:28
Speaker A
то есть мы видим что элемент как было четыре так 4 и осталось это тоже вполне ожидаемо потому что они в отличие от базового мосина предаются как раз по значению они по ссылке то есть мы можем сколько угодно их изменять в нашей
19:41
Speaker A
функции и от этого ничего не изменится а что если мы хоть им все же что то добавить в переданы слайс но при этом не хотим изменять внешний и здесь выход только один нам нужно создать новый слайд внутри функции и скопировать туда
19:54
Speaker A
переданный во-первых создаем новый слайд воспользуемся функцией чтобы у него были корректная длина и емкость в данном случае я емкость задавать не будут так как мне это не нужно но зависимости от ваших целей вы можете присвоить какое-то свое значение далее
20:10
Speaker A
мы вызываем встроенную функцию копии она принимает два аргумента первый аргумент это целевой слайд стоит тот который мы копируем значения а второй элемент это исходный то есть то слазь из которого мы берем значения то есть здесь мы указываем только что созданный слайс а
20:27
Speaker A
сюда записываем переданный и ниже заменяем переменную лист на юрист теперь запускаем и смотрим что получилось что уж теперь результат вполне адекватные внешне слайс у нас никак не изменился а во внутренние добавился новый элемент таким образом мы приходим к следующему советую если мы хотим
20:48
Speaker A
как-то изменить переданы слайс но при этом не хотим затрагивать внешней the applied изменением нам сначала надо создать копию этого слайс а на самом деле в некоторых случаях мы действительно хотим поменять внешне слайс например если мы хотим его каким-то образом отсортировать но при
21:03
Speaker A
этом не хотим тратить память на создания еще одного то есть мы собираемся отсортировать элементы прямо внутри слайсы но важно уделять те случаи когда мы целенаправленно изменяем переданы слайс от тех случаев когда мы это делаем случайно что же двигаемся дальше и
21:17
Speaker A
возвращаемся к обсуждению слайс of теперь фида мы лучше прочувствовали бутыль работу слайсами можно поговорить об одной более хитрый и менее очевидной вещи давайте избавимся от лишнего и создадим слайс с четко заданными размерами и емкостью пусть это все еще
21:33
Speaker A
будет слайд из интерьеров длина у него будет 4 и емкость также 4 давайте выведем этот слазь и убедимся что он состоит из нулей да действительно он состоит из четырех нуле и потому что нулевые значения интеджер а это 0 теперь
21:46
Speaker A
давайте добавим в него элемент и присвоим это новой переменной это будет например лист 2 и добавляем новый элемент наш слайд пусть это будет единичка теперь давайте по меня м первый элемент у каждой из этих переменных у переменной лист пусть это будет пятерка
22:03
Speaker A
а о переменной лист 2 например девяткой а теперь мы видим содержимое обоих слайс of на экран и посмотрим что получилось и здесь нас ничего не удивляет мы видим ровно то что ожидали у первого слоя со первый элемент эта пятерка а у второго
22:17
Speaker A
девятка но что если мы изначально создадим слои с ёмкостью нее четыре опять давайте это поменяем и посмотрим что получится запускаем и здесь мы видим более интересный результат по какой-то причине теперь у обоих слайс of первый элемент это девятка хотя мы первому
22:34
Speaker A
слайду все еще и присваиваем пятерку но на самом деле этот результат все также вполне ожидаем первом случае емкость была равна 4 и элементов также было 4 и когда мы решили добавить в этот слайд еще один элемент функция append создала
22:48
Speaker A
новый массив и скопировал туда все значения и в итоге в переменных лист и лист 2 ежат слайсы с разными базовыми массивами естественное изменение одного из них никак не повлияет на другой и в общем случае нам не стоит пытаться
23:01
Speaker A
догадываться как поведет себя функцию append то есть будет на пересоздавать базовый массив или же нет техническим и конечно же можем это понять как настоящий разработчики мы конечно можем поесть в исходный код g и посмотреть как устроена функция которая занимается
23:16
Speaker A
увеличением размера базово массива эта функция называется гроуз лоис и она действительно удваивает размер массива но поступает на так не во всех случаях а только бте когда размер базовом asio меньше 1024 если же массив больше то в таком случае емкость увеличивается всего
23:31
Speaker A
лишь на четверть но на самом деле все это не имеет никакого значения и я вам показал это просто для расширения кругозора во-первых следить за емкостью и размерам всех своих слайс от довольно трудозатратно и на самом деле практически всегда бесполезно а
23:45
Speaker A
во-вторых мы никогда не знаем как было в версиях go изменится поведение внутренних функций то есть возможно в новой версии языка размер базового массива будет увеличиваться не в два в три раза или же большим массивом будет считаться не массив из 1024 элементов а
24:00
Speaker A
например из двух тысяч и в таком случае нас конечно же все сломается кроме этого мы какой-то момент можно вообще захотите использовать другу реализацию год то есть например и кто-нибудь другой компилятор и там это может работать по другому то есть завязываться на
24:13
Speaker A
конкретную реализацию в конкретной версии языка ни в коем случае не стоит а мораль всей этой истории такова что когда мы пользуемся функция append результат ее работы нужно присваивать не новой переменной а той же самой то есть нам не стоит здесь сдавать переменную с
24:29
Speaker A
именем лист 2 в таком случае поведение всегда будет ожидаемым и мы не встретимся снизить не с этими сюрпризами итого мы получаем следующий совет результат работы функции append нужно присваивать тоже самой переменной что ж надеюсь это понятно и двигаемся дальше
24:43
Speaker A
следующий пример который я хочу вам показать он более часто и встречается намного реже чем предыдущие поэтому я даже не стала выносить в отдельный совет и пытаться как-то это обобщать я просто вам покажу в чем заключается ещё одна проблема и покажу как ее можно избежать
24:58
Speaker A
данную ситуацию я никогда не стучал своей работе и нашел тот примеров блоге авторов языках например мы хотим написать функцию которая будет считывать целиком файл и искать в нем какую-то последовательность байтов выглядеть это будет следующим образом во первых скидываем файл
25:17
Speaker A
здесь мы игнорируем возвращаем ую ошибку потому что для нашего примера она абсолютно не важно и для того чтобы найти файлы нужную последовательность байтов мы воспользуемся регулярным выражением например нас интересует только цифры применяем регулярные выражения и возвращаем результат запускать эту функцию не буду но
25:40
Speaker A
расскажу в чем заключается проблема а проблема в том что файл который мы испытываем может оказаться очень большим как вы понимаете это может быть даже если гигабайт информации но при этом может получить так что нас интересует лишь небольшая его часть то есть в
25:54
Speaker A
результате применения регулярного выражения мы можем получить слайс размером всего лишь в 10 элементов но как мы помним у этого слайсы останется все тот же старый базовый массив то есть получается такая ситуация что на протяжении всей работы нашей программы
26:08
Speaker A
то есть получается такая ситуация что мы и на протяжении всей работы нашей программы оперируем с лайсом всего лишь из 10 элементов но программа у нас съедает несколько гигабайт памяти а что если мы испытываем файлы не а множество раз мы в какой-то момент попросту съедим
26:23
Speaker A
всю память нашего компьютера и программа работать не будет и чтобы избежать такой проблемы мы просто можем создать новый слайд и приложить туда элементы во первых создаем слайс его длина будет равна размеру полученного слайс а емкость мы здесь не
26:41
Speaker A
указываем и поэтому она будет равна длине то есть это как минимум не несколько гигабайт далее мы вызываем функцию копии и прикладываем значение из одного слоя со в другой и в конце мы возвращаем то слазь который только что создали то есть таком случае когда мы
26:56
Speaker A
выходим из функций фан digits слайс которая лежит в переменные by не будет нигде использоваться и его просто почистить сборщик мусора и кстати с помощью функции append можно было бы написать более красивый вариант этой функции и я предлагаю вам сделать это
27:10
Speaker A
самостоятельно в качестве упражнения а мы тем временем закончили с разбором полезных практик и рекомендации и теперь как я и обещал мы переходим к описанию собственной функции append напишем ее имя с большой буквы как минимум чтобы она отличалась от встроенной функции и
27:24
Speaker A
принимать или будет всего два аргумента это слайд в который мы хотим что-то добавить и добавляем элемент возвращаем мы конечно же также слайс и здесь мы сразу видим два существенных отличий от стандартного open да во первых работаем мы только с интерьерами и во-вторых
27:40
Speaker A
добавляем мы только один элемент в отличие от стандартного слайсы который позволяет добавлять сразу множество элементов но для учебного примера нам этого вполне достаточно во-первых создадим переменную в которую сохраним результат размер итогового слайс а должен быть на единичку больше чем у исходного давайте
27:58
Speaker A
сохранив поэтому значение также в отдельную переменную теперь нам нужно проверить влезет ли итоговый слайд в емкость предыдущего то есть хватит при в его базовом мазь или место для еще одного элемента проверяется это достаточно просто и если запаса емкости хватает то мы просто
28:17
Speaker A
расширяем исходный слайс на единичку и сохраняем его в переменную для результата если же место в базовом массиве закончилась то дальше будет веселее теперь нам нужно вычислить любая емкость будет у итогового слайс а и как мы обсуждаем теоретической части мы можем
28:34
Speaker A
просто удвоить размер исходного слайсы давайте так и поступим [музыка] но на самом деле этот код работает не во всех случаях я снова предлагаю вам поставить это видео на паузу и попробовать догадаться таком случае код сломается а сломается он в том случае если размер
28:53
Speaker A
исходного слоя равен нулю то есть сколько бы раз мы его не умножали на 2 он всегда останется нулем и решить эту проблему можно несколькими способами самое простое это просто всегда добавляете единичку к размеру исходного слайс а но для того чтобы результат
29:07
Speaker A
всегда корректно удваивался и не вызывал нашего удивления давайте поступим чуть сложнее во-первых изначально нашу емкость будет равна размеру исходного слоя увеличенному на единичку и такое значение у нас уже есть это размер итогового слайс а давайте просто им воспользуемся и присвоим это значение
29:24
Speaker A
ёмкости и теперь если получилось так что результирующая емкость меньше чем удвоенные размера исходного слайсы то вот в таком случае мы будем удваивать этот мир вот теперь поведение функции будет более очевидной а теперь нам нужно создать новый слайд у которого будут параметры
29:45
Speaker A
которые мы только что определили то есть мы укажем для него необходимый размер и емкость и скопируем в него содержимое исходного слайс а теперь нам осталось только положить в последнюю ячейку итогового слайсы значение которое мы хотели в него добавить и
30:03
Speaker A
возвращаем результат теперь давайте проверим корректно не работать наша функция создаем слайс для примера и сделаем это с помощью функции мейк для начала зададим ему длину равную емкости в таком случае его емкость должна удвоиться вызываем функцию append и присваиваем результат переменной лист
30:24
Speaker A
и добавим мы например сюда единичку изначально конечно же слайд будет заполнить нулями но нам это не важно так же давайте выведем на экран содержимое этого слоя и его емкость и размер запускаем и смотрим что получилось видим что действительно размер слайс
30:42
Speaker A
увеличился на единичку потому что добавился новый или вот он а емкость удвоилось потому что именно так мы и хотели но какой смысл писать собственную функцию если она повторяет поведение стандартной давайте сделаем так чтобы емкость например увеличилась не в два в
30:56
Speaker A
три раза для этого заменяем двойку на тройку и запускаем еще раз и да теперь мы видим что емкость теперь стало в три раза больше теперь давайте сделаем так чтобы емкость никак не изменялась то есть чтобы ее хватало изначально
31:09
Speaker A
например зададим ее равной 5 запускаем программу снова и смотрим на результат и мы видим что функция работает именно так как мы и ожидаем что же можно считать что это успех и в качестве упражнения я бы предложила вам немножко улучшить эту
31:23
Speaker A
функцию то есть приблизить ее функционал от стандартной функции append можно сделать так чтобы она получала ни один элемент а сколько угодно синтаксически это делается следующим образом имени тип аргумента мы просто добавляем три точки все теперь мы можем передавать ей
31:37
Speaker A
сколько угодно значений но естественно сейчас оно не будет работать корректно и она даже не из компилируется потому что теперь передаваемый аргумент считается не интеджер am a slight сам без интерьеров и соответственно с ним нужно правильно работать что же и теперь я
31:52
Speaker A
могу сказать что я рассказал вам о сланцах все что хотел спасибо что досмотрели это видео до конца пишите в комментариях понравилась ли она вам было ли оно для вас интересным и полезным и так же подписывайтесь чтобы не пропустить выход следующих видео
Topics:GoLangслайсысрезымассивыappendвнутреннее устройстводинамические массивыGoпрограммированиеНиколай Тузов

Frequently Asked Questions

Что такое слайс в Go и как он связан с массивом?

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

В чем разница между длиной и емкостью слайса?

Длина слайса — это количество элементов, которые он фактически использует, а емкость — максимальное количество элементов, которые могут быть размещены в базовом массиве, начиная с первого элемента слайса.

Как работает функция append в Go с слайсами?

Функция append добавляет новый элемент в слайс, увеличивая его длину. Если емкость позволяет, элемент перезаписывает существующую ячейку базового массива; иначе происходит выделение новой памяти.

Get More with the Söz AI App

Transcribe recordings, audio files, and YouTube videos — with AI summaries, speaker detection, and unlimited transcriptions.

Or transcribe another YouTube video here →