Контекстуализация срезов в Go

Контекстуализация срезов в Go Изучение

Go — это язык высокого уровня с функциями языка низкого уровня. Он был разработан Робертом Гриземером, Робом Пайком и Кеном Томпсоном и выпущен Google в 2012 году. Go поддерживает языковые конструкции и характеристики высокого уровня, такие как сборка мусора., дженерики Golang, высокопроизводительные сети и параллелизм Go. В то же время он предлагает реализацию и контроль, которые имеют низкоуровневые характеристики. Например, он обеспечивает высокоуровневую поддержку параллелизма через горутины, а также через каналы, но с пакетом также можно использовать низкоуровневую функциональность sync/atomicдля обеспечения потокобезопасной синхронизации. Он статически типизирован, полностью скомпилирован и, следовательно, обеспечивает лучшую эффективность во время выполнения (по сравнению с Java, Python, JavaScript и другими интерпретируемыми языками).

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

В языке Go есть специальная структура данных, называемая срезом, которая обеспечивает мощный и эффективный способ представления массивов благодаря своему динамическому размеру и гибкости.

Срезы на языке Go

Срез — это массив переменной длины, который может хранить элементы одного типа. Внутри срез является ссылкой на базовый массив. Срез всегда начинается с 0индекса, а последний элемент среза находится в N-1индексе, где Nдлина среза. Размер Cбазового массива известен как емкость среза, где Cон всегда больше или равен N.

Срез, указатель и массив: наглядное объяснение

Go можно рассматривать как язык семейства C и обеспечивает поддержку указателей и массивов. Однако из соображений безопасности существуют ограничения на указатели Go (по сравнению с указателями C). Кроме того, Go поддерживает гибкие и динамичные слайсы.

На следующей диаграмме показано наглядное сравнение массива, указателя и среза. Разметка памяти слайса в Go — это структура, которая состоит из указателя на массив и двух переменных ( lenи capуказывающих длину и емкость слайса соответственно). Указатель содержит адрес памяти значения. Тип *Tявляется указателем на значение T. Хотя длина массива фиксирована, срез и указатель могут указывать на любой элемент массива (адрес памяти). Хотя указатель не имеет определенного размера или емкости, структура памяти среза в Go содержит переменные для хранения длины и емкости среза.

Читайте также:  Дорожная карта для создания вакансий в аэрокосмической отрасли: как стать аэрокосмическим программистом

Схема среза, указателя и массива

Схема среза, указателя и массива

Срез или массива

Размер массива должен быть определен при определении переменной массива или […]должен использоваться в объявлении массива, чтобы компилятор Go мог определить его автоматически. Если в квадратных скобках ничего не указано, то создается срез. Действительные индексы как для массивов, так и для срезов: from 0и l-1where l— длина массива или среза. Более того, размер массива не может быть изменен после создания, однако слайс в этом контексте является гибким.

Еще одно отличие возникает при работе с аргументами функции. Все аргументы функции передаются по значению на языке Go. Поэтому при передаче массива в функцию создается копия этого массива и передается в функцию. Следовательно, изменения в массиве, сделанные внутри функции, теряются при выходе из функции. Напротив, как упоминалось выше, срез — это заголовок, содержащий указатель на базовый массив. Следовательно, при передаче фрагмента в функцию создается копия этого заголовка и передается в функцию. Следовательно, передача аргумента с использованием среза выполняется быстрее, а также сохраняет любые изменения, выполненные в функции на исходном срезе.

Поэтому, учитывая эту гибкость и мощь слайса, слайс обычно предпочтительнее массива при программировании на Go. Тем не менее, массивы по-прежнему полезны в Go, когда требуется детальное распределение памяти. Например, при чтении.wav(аудио) файла имеется информационный заголовок с фиксированной структурой. Многие поля в этом заголовке обычно не имеют значения при реализации. При фиксации записи/чтения в этом типе файла в Go определяется структура, содержащая нужные поля. Между ними определяются массивы соответствующего размера, чтобы позаботиться о неважных полях в заголовке аудиофайла.

Срез или указатели

Указатель представлен как *Tтип Tхранимого значения. Например, в ptr *int, ptrэто указатель на int. Оператор *_разыменовывает указатель, в то время как &оператор предоставляет адрес переменной (которая также является указателем на переменную).

В то время как аргументы функций в Go передаются по значению, указатели — это один из способов избежать накладных расходов на копирование при передаче структур и массивов. Кроме того, указатели на структуры удобны при создании структур данных, таких как связанные списки и двоичные деревья. Для большей ясности о внутреннем расположении указателя в языке Go обратитесь к рисунку и обсуждению в этом уроке по языку Go. Однако Go не поддерживает арифметику указателей, доступную в C. По сравнению с указателями срезы передаются функции без необходимости использования указателя, поскольку Go передает указатель на базовый массив среза внутри.

Связь между срезом и массивом

Каждый срез основан на базовом массиве с длиной, равной емкости среза. Если существующий массив связан с фрагментом, любые изменения в фрагменте влияют на указанный массив. Однако при изменении емкости среза содержимое старого базового массива копируется в новый массив с обновленной емкостью, а срез указывает на новый массив. Для лучшего понимания обратитесь к примеру кодирования в этом уроке по языку Go.

Краткая прогулка по срезу

Срез можно создать следующими способами:

  1. С пустым фрагментом, используя varключевое слово следующим образом: var aSlice []datatype.
  2. С синтаксисом массива без указания размера массива для объявления среза. Например, aSliceArray := []datatype {value1, value2,…, valueN}.
  3. Нарезая существующий массив, чтобы определить новый срез. Например,
    anArray := [length]datatype {value1, value2,…, valueN}
    aSliceArray := anArray[i1:i2], i1, и i2являются здесь искомыми индексами.
  4. Со срезом по newключевому слову. Например, aSliceArray := new([capacity] datatype)[0:length].
  5. Объявив срез с помощью make()функции. Например, aSliceArray := make([]datatype, length, capacity).

Примечание. Для случаев 3–5 выше значения lengthи capacityдолжны быть определены в коде во время объявления.

В следующем виджете кода в строках 10–24 показаны различные способы создания (объявления или инициализации) intсреза типа. Кроме того, в строке 31 показано, что также могут быть определены срезы других типов (например, string). Функция reflect.ValueOf(var).Kind()в строках 32 и 40 возвращает имя типа данных kind ( slice). Функции len(var)и cap(var)в строках 32 и 41 возвращают длину и емкость среза. Оператор ==может использоваться для определения того, является ли срез nilили нет (см. строки 33–34 ). Однако, сравнивая два среза с помощью==оператор приведет к ошибке. (Пожалуйста, запустите следующий виджет кода еще раз после раскомментирования строки 36. )

package main
import (
    «fmt»
    «reflect»
)
func main() {
    //Creating and using an empty slice
    var intSlice []int
    printSlice(intSlice)
    // A slice using array
    array := [4]int {0, 5, 10, 15}
    aSlice1 := array[0:4]
    // A slice using array syntax without specifying array size
    aSlice2 := []int {1, 6, 11, 16}
    // A slice using new keyword
    aSlice3 := new([10]int)[0:4]
    // A slice using the make() function
    aSlice4 := make([]int, 4, 10)
    printSlice(aSlice1)
    printSlice(aSlice2)
    printSlice(aSlice3)
    printSlice(aSlice4)
    var aSlice5 = []string{«Monday», «Tuesday», «Wednesday», «Thursday», «Friday», «Saturday», «Sunday»}
    fmt.Printf(«%s %s len=%v cap:%v\n», «string-type», reflect.ValueOf(aSlice5).Kind(), len(aSlice5), cap(aSlice5))
    fmt.Println(intSlice == nil)
    fmt.Println(aSlice1 == nil)
    //Uncomment following to see error: Comparing two slices using ==
    //fmt.Println(aSlice1 == intSlice)
}
func printSlice(s []int) {
    fmt.Print(reflect.ValueOf(s).Kind())
    fmt.Printf(» len=%d cap=%d %v\n», len(s), cap(s), s)
}

После создания слайса можно использовать различные операции со слайсами для добавления, доступа и изменения элементов слайса. Следующий виджет кода показывает синтаксис операций доступа и модификации ( строки 12–13 ) в intсрезе. Строки 17–19 демонстрируют добавление новых элементов в срез с помощью append()метода. Однако в языке Go нет встроенного метода для удаления элемента из среза по соображениям оптимизации. Эта задача решается путем определения функции remove_element(intArray []int, index int) []intв строках 25–27, которая разумно использует встроенный append()метод.

package main
import (
    «fmt»
//  «reflect»
)
func main() {
    //Add, access, change, and append slice elements
    aSliceArray := make([]int, 2, 4)
    aSliceArray[0] = 1
    aSliceArray[1] = 2
    fmt.Println(«Slice contents:», aSliceArray)
    fmt.Printf(«len=%d cap=%d\n», len(aSliceArray), cap(aSliceArray))
    aSliceArray = append(aSliceArray, 3, 4, 5, 6, 7)
    fmt.Println(«Slice after append():», aSliceArray)
    fmt.Printf(«len=%d cap=%d\n», len(aSliceArray), cap(aSliceArray))
    aSliceArray = remove_element(aSliceArray, 3)
    fmt.Printf(«Slice after removal: %d \nlen=%d cap=%d\n», aSliceArray, len(aSliceArray), cap(aSliceArray))
}
func remove_element(intArray []int, index int) []int {
    return append(intArray[:index], intArray[index+1:]…)
}

Заключение

Короче говоря, Go — идеальный язык программирования для изучения с таким количеством привлекательных функций. Если вы заинтересованы в изучении дополнительных ресурсов, обратитесь к следующим курсам и не забудьте поделиться с нами своими отзывами и мнениями!

Оцените статью
bestprogrammer.ru
Добавить комментарий