Шаг 49.
Язык программирования Go.
Изменение срезов
На этом шаге рассмотрим изменение срезов в Go.
Для добавления новых значений в конец среза можно использовать встроенную функцию append(). Эта функция принимает срез и
одно или более значений добавляемых отдельных элементов. При
необходимости добавить содержимое другого среза следует использовать оператор ... (многоточие), чтобы сообщить компилятору Go,
что содержимое указанного среза должно добавляться поэлементно.
Добавляемые значения должны иметь тот же тип, что и сам срез.
При работе со строками оператор многоточия можно использовать
для добавления отдельных байтов из строки в срез с байтами.
Задание 1. Реализовать различные методы добавления элементов в срез (рис.1):
Рис.1. Пример работы приложения
Раскрыть/скрыть решение и комментарии.
s := []string{"А", "Б", "В", "Г", "Д", "Е"}
t := []string{"И", "Й", "К", "Л"}
u := []string{"к", "л", "м", "н", "о", "п"}
b := []byte{'A', 'B'}
s = append(s, "ё", "ж", "з") // Добавить отдельные значения
s = append(s, t...) // Добавить все элементы из среза t
s = append(s, u[2:5]...) // Добавить часть элементов из среза u
letters := "cde"
b = append(b, letters...) // Добавить байты из строки в срез с байтами
fmt.Printf("Получить:\ns = %v\nb = %s\n", s, b)
Архив примера можно взять здесь.
Встроенная функция append() принимает срез и одно или более добавляемых значений и возвращает (возможно, новый) срез,
включающий содержимое оригинального среза, плюс указанное
значение или значения, находящиеся в последних элементах. Если оригинальный срез имеет достаточную емкость (то есть сумма
его длины и количества новых элементов не превышает емкости),
функция append() вставит новые значения в конец среза и вернет
оригинальный срез с длиной, увеличенной на количество добавленных элементов. Если оригинальный срез имеет недостаточную
емкость, функция append() создаст новый срез, скопирует в него
элементы из оригинального среза, добавит в конец новые значения
и вернет новый срез – именно поэтому необходимо присваивать
значение, возвращаемое функцией append(), оригинальной переменной.
Иногда бывает необходимо вставлять элементы не в конец, а в
начало или в середину среза.
Задание 2. Пример применения пользовательской функции InsertStrCpy(),
принимающей срез, куда вставляются элементы, срез, элементы которого требуется вставить, и номер позиции для вставки (рис.2):
Рис.2. Пример работы приложения
Раскрыть/скрыть решение и комментарии.
Функция InsertStrCpy() создает новый срез,
вызывает встроенную функцию copy(), чтобы скопировать содержимое первого среза, и вставляет содержимое второго среза.
func InsertStrCpy(slice, insertion []string, index int) []string {
/*Функция начинается с создания нового среза (result), достаточно большого,
чтобы хранить элементы из обоих срезов, переданных функции*/
result := make([]string, len(slice)+len(insertion))
//В срез result копируется фрагмент первого среза (slice[:index])
at := copy(result, slice[:index])
//В срез result, начиная с позиции at, копируется все содержимое среза insertion
at += copy(result[at:], insertion)
//Копируется остальное содержимое первого среза (slice[index:])
copy(result[at:], slice[index:])
//Срез result возвращается вызывающей программе
return result
}
Архив примера можно взять здесь.
Встроенная функция copy() принимает два среза (которые могут быть фрагментами одного и того же среза, причем даже перекрывающимися фрагментами), содержащие элементы одного типа. Она
копирует элементы из второго (исходного) среза в первый (целевой)
срез и возвращает количество скопированных элементов. Если исходный срез пуст, функция copy() ничего не сделает. Если длины
целевого среза будет недостаточно, чтобы принять элементы из исходного среза, непоместившиеся элементы просто будут игнорироваться. Если емкость целевого среза больше его текущей длины,
перед копированием длину можно увеличить до полной емкости с
помощью инструкции срез = срез [:cap(срез)].
Если в аргументе index передать 0, выражение slice[:index] в
первом вызове функции copy() примет вид slice[:0] (то есть пустой
срез), поэтому ничего копироваться не будет. Аналогично если в
аргументе index передать значение, большее или равное длине среза
slice, выражение slice[index:] в последнем вызове функции copy()
фактически примет вид slice[len(slice):] (то есть пустой срез), поэтому и в этой ситуации ничего не копируется.
Срезы, передаваемые встроенной функции copy(), должны иметь
одинаковый тип. Исключение составляет случай, когда первый (целевой) срез имеет тип []byte. В этой ситуации второй (исходный)
аргумент может иметь тип []byte или string. Если второй аргумент
имеет тип string, функция просто скопирует байты строки в первый
аргумент.
Задание 3. Удаление элементов в начале, конце и середине среза.
Раскрыть/скрыть решение и комментарии.
Удаление элементов в начале среза легко реализуется с помощью
операции извлечения среза.
s := []string{"A", "B", "C", "D", "E", "F", "G"}
s = s[2:] // Удалит s[:2] из начала
fmt.Println(s)
[C D E F G]
Удаление элементов в конце среза также выполняется с помощью
простой операции извлечения среза.
s := []string{"A", "B", "C", "D", "E", "F", "G"}
s = s[:4] //Удалит s[4:] в конце
fmt.Println(s)
[A B C D]
Например, получить три элемента из середины среза s можно с помощью выражения s[2:5]. Но удалить элементы из середины среза не
так просто. При удалении из середины среза можно воспользоваться функцией append(),
добавляющей фрагмент среза s, следующий за фрагментом, который
требуется удалить, в конец фрагмента, предшествующего удаляемому,
и присваиванием получившегося среза обратно переменной s.
s := []string{"A", "B", "C", "D", "E", "F", "G"}
s = append(s[:1], s[5:]...) // Удалит s[1:5] из середины
fmt.Println(s)
[A F G]
На следующем шаге рассмотрим функции пакета sort в Go для сортировки и поиска по срезам.
Предыдущий шаг
Содержание
Следующий шаг