Публикации - Go

Типы данных - Основные типы данных, однотипные - Срезы

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

Вы можете создать срез с помощью make() или как массив, не указывая его размера или используя [...]. Если инициализировать срез не требуется, то лучше и быстрее использовать make(). Однако если вы хотите инициализировать его во время создания, то make() уже не подойдет. Как итог‚ вы можете создать срез с тремя элементами float64 с помощью

aSlice := []float64{1.2, 3.2, -4.5}

Создать срез‚ вмещающий те же три элемента‚ с помощью make() можно так:

var users []string = make([]float64, 3)
aSlice[0] = 1.2
aSlice[1] = 3.2
aSlice[2] = -4.5

Как срезы, так и массивы могут иметь много измерений — создать срез с двумя измерениями с помощью make() так же просто:

make([][]int, 2)

Оператор возвращает срез двумя измерениями, где первое равно 2 (строки), а второе (столбцы) не определено и должно быть явно указано при добавлении в него данных.

Если необходимо определить и инициализировать срез с двумя измерениями одновременно, то можем сделать следующее:

twoD := [][]int{{1, 2, 3},{4, 5, 6}}

Длину массива или среза можно получить с помощью len(). Вы можете добавлять новые элементы к полному срезу с помощью функции append().

package main

import "fmt"

func main() {
	// Create an empty slice
	aSlice := []float64{}
	// Both length and capacity are 0 because aSlice is empty
	fmt.Println(aSlice, len(aSlice), cap(aSlice))

	// Add elements to a slice
	aSlice = append(aSlice, 1234.56)
	aSlice = append(aSlice, -34.0)
	fmt.Println(aSlice, "with length", len(aSlice))

	// A slice with length 4
	t := make([]int, 4)
	t[0] = -1
	t[1] = -2
	t[2] = -3
	t[3] = -4
	// Now you will need to use append
	t = append(t, -5)
	fmt.Println(t)

	// A 2D slice
	// You can have as many dimensions as needed
	twoD := [][]int{{1, 2, 3}, {4, 5, 6}}

	// Visiting all elements of a 2D slice
	// with a double for loop
	for _, i := range twoD {
		for _, k := range i {
			fmt.Print(k, " ")
		}
		fmt.Println()
	}

	make2D := make([][]int, 2)
	fmt.Println(make2D)
	make2D[0] = []int{1, 2, 3, 4}
	make2D[1] = []int{-1, -2, -3, -4}
	fmt.Println(make2D)
}

Ёмкость среза, cap()

У срезов также есть и дополнительное свойство — емкость (capacity),которое можно получить с помощью функции cap().

Вот небольшая Go-программа, в которой показаны свойства длины и емкости срезов.

package main

import "fmt"

func main() {
	// Only length is defined. Capacity = length
	a := make([]int, 4)
	fmt.Println("L:", len(a), "C:", cap(a))
	// Initialize slice. Capacity = length
	b := []int{0, 1, 2, 3, 4}
	fmt.Println("L:", len(b), "C:", cap(b))
	// Same length and capacity
	aSlice := make([]int, 4, 4)
	fmt.Println(aSlice)
	// Add an element
	aSlice = append(aSlice, 5)
	fmt.Println(aSlice)
	// The capacity is doubled
	fmt.Println("L:", len(aSlice), "C:", cap(aSlice))
	// Now add four elements
	aSlice = append(aSlice, []int{-1, -2, -3, -4}...)
	fmt.Println(aSlice)
	// The capacity is doubled
	fmt.Println("L:", len(aSlice), "C:", cap(aSlice))
}

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

Запись наподобие make([]int, 3, 2) генерирует сообщение об ошибке, поскольку в любой момент времени емкость среза (2) не может быть меньше его длины (3).

Установка правильной емкости среза, если она известна заранее, ускорит ваши программы, так как Go не придется выделять новый базовый массив и копировать все данные.

Выбор части среза

Go позволяет выбирать части среза при условии, что все нужные элементы расположены рядом друг с другом.

С помощью нотации [1:] можно пропустить первый элемент.

package main

import "fmt"

func main() {
	aSlice := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
	fmt.Println(aSlice)
	l := len(aSlice)

	// Первые 5 элементов
	fmt.Println(aSlice[0:5])
	// Первые 5 элементов
	fmt.Println(aSlice[:5])

	// Последние 2 элемента
	fmt.Println(aSlice[l-2 : l])

	// Последние 2 элемента
	fmt.Println(aSlice[l-2:])

	// Первые 5 элементов
	t := aSlice[0:5:10]
	fmt.Println(len(t), cap(t))

	// Элементы по индексам 2,3,4
	t = aSlice[2:5:10]
	fmt.Println(len(t), cap(t))

	// Элементы по индексам 0,1,2,3,4
	t = aSlice[:5:6]
	fmt.Println(len(t), cap(t))
}

Функция copy()

Go содержит функцию copy()‚ предназначенную для копирования существующего массива в срез или существующего среза в другой срез.

В следующей программе показано использование функции copy(). Введите ее в текстовом редакторе и сохраните как copySlice.go:

package main

import "fmt"

func main() {
	a1 := []int{1}
	a2 := []int{-1, -2}
	a5 := []int{10, 11, 12, 13, 14}
	fmt.Println("a1", a1)
	fmt.Println("a2", a2)
	fmt.Println("a5", a5)

	// copy(destination, input)
	// len(a2) > len(a1)
	copy(a1, a2)
	fmt.Println("a1", a1)
	fmt.Println("a2", a2)

	// len(a5) > len(a1)
	copy(a1, a5)
	fmt.Println("a1", a1)
	fmt.Println("a5", a5)

	// len(a2) < len(a5) -> OK
	copy(a5, a2)
	fmt.Println("a2", a2)
	fmt.Println("a5", a5)
}

Сортировка

Пакет sort может сортировать срезы встроенных типов данных, при этом вам не придется писать дополнительный код. Кроме того, Go предоставляет функцию sort.Reverse() для сортировки в порядке, обратном порядку по умолчанию. Однако интересен тот факт, что sort позволяет писать собственные функции сортировки для пользовательских типов данных, реализуя интерфейс sort.Interface.

package main

import (
	"fmt"
	"sort"
)

func main() {
	sInts := []int{1, 0, 2, -3, 4, -20}
	sFloats := []float64{1.0, 0.2, 0.22, -3, 4.1, -0.1}
	sStrings := []string{"aa", "a", "A", "Aa", "aab", "AAa"}

	fmt.Println("sInts original:", sInts)
	sort.Ints(sInts)
	fmt.Println("sInts:", sInts)
	sort.Sort(sort.Reverse(sort.IntSlice(sInts)))
	fmt.Println("Reverse:", sInts)

	fmt.Println("sFloats original:", sFloats)
	sort.Float64s(sFloats)
	fmt.Println("sFloats:", sFloats)
	sort.Sort(sort.Reverse(sort.Float64Slice(sFloats)))
	fmt.Println("Reverse:", sFloats)

	fmt.Println("sStrings original:", sStrings)
	sort.Strings(sStrings)
	fmt.Println("sStrings:", sStrings)
	sort.Sort(sort.Reverse(sort.StringSlice(sStrings)))
	fmt.Println("Reverse:", sStrings)
}

Количество комментариев: 0

Для того, чтобы оставить коментарий необходимо зарегистрироваться