Выражения среза в Go
В Golang есть много отличных знакомств с ломтиками:
Эта история посвящена исключительно выражениям срезов. Они могут создавать два типа значений:
- подстрока из строкового операнда
- фрагмент из массива, указатель на массив или сам фрагмент
Спецификация языка определяет два типа выражений среза - простые и полные ...
Простые выражения среза
Наиболее известная форма выражения среза:
вход [низкий: высокий]
Индексы low и high должны быть целыми числами. Они указывают, какие элементы операнда (input) помещаются внутри результирующего фрагмента или строки. Результат содержит элементы операнда, начиная с low (включительно) до high (исключительно). Операнд - это строка, массив, указатель на массив или срез (площадка):
fmt.Println("foobar"[1:3]) // "oo" numbers := [5]int{1, 2, 3, 4, 5} fmt.Println(numbers[1:3]) // [2, 3]
Длина результата
high — low
Применение выражения среза к указателю массива является сокращением для первого разыменования такого указателя, а затем регулярного применения выражения среза (площадка):
numbers := [5]int{1, 2, 3, 4, 5} fmt.Println((&numbers)[1:3]) // [2, 3]
Индексы low или high можно не указывать. Затем используются значения по умолчанию. Для low это 0, а для high это длина операнда (площадка):
fmt.Println("foo"[:2]) // "fo" fmt.Println("foo"[1:]) // "oo" fmt.Println("foo"[:]) // "foo"
Индексы не могут быть произвольными числами (площадка):
- отрицательные числа не допускаются
- низкий ≤ высокий
- high ≤ len (ввод)
//fmt.Println("foo"[-1:]) // invalid slice index -1 (index must be non-negative) //fmt.Println("foo"[:4]) // invalid slice index 4 (out of bounds for 3-byte string) fmt.Println("foo"[2:2]) // ""(blank) //fmt.Println("foo"[2:1]) // invalid slice index: 2 > 1
Если индексы вне диапазона не могут быть обнаружены при компиляции, возникает паника во время выполнения (игровая площадка):
func low() int { return 4 } func main() { fmt.Println("foo"[low():]) } panic: runtime error: slice bounds out of range goroutine 1 [running]: panic(0x102280, 0x1040a018) /usr/local/go/src/runtime/panic.go:500 +0x720 main.main() /tmp/sandbox685025974/main.go:12 +0x120
Полные выражения среза
Применяется только к массиву, указателю на массив или фрагменту (строки исключаются). Он позволяет контролировать емкость возвращаемого среза. С помощью простого выражения среза емкость возвращаемого среза - это максимально возможная емкость, начиная с low, то есть cap(input) — low
(площадка):
numbers := [10]int{0,1,2,3,4,5,6,7,8,9} s := numbers[1:4] fmt.Println(s) // [1, 2, 3] fmt.Println(cap(s)) // 9
Для массива a
cap(a) == len(a)
В приведенном выше фрагменте емкость s равна 9, поскольку срез начинается с индекса 1, а в базовом массиве есть еще 8 элементов (2–9). Выражения полного среза позволяют изменить это поведение по умолчанию (игровая площадка):
numbers := [10]int{0,1,2,3,4,5,6,7,8,9} s := numbers[1:4:5] fmt.Println(s) // [1, 2, 3] fmt.Println(cap(s)) // 4
Выражение полного среза имеет следующий синтаксис:
вход [низкий: высокий: макс]
Индексы low и high работают так же, как и с простыми выражениями среза. Единственное отличие - max, при котором размер результата устанавливается равным max — low
(площадка):
numbers := [10]int{0,1,2,3,4,5,6,7,8,9} s := numbers[2:4:6] fmt.Println(s) // [2, 3] fmt.Println(cap(s)) // 4
При нарезке операнда, который является срезом, емкость зависит от операнда, а не от базового массива (площадка):
numbers := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} fmt.Println(cap(numbers)) // 10 s1 := numbers[1:4] fmt.Println(s1) // [1, 2, 3] fmt.Println(cap(s1)) // 9 s2 := numbers[1:4:5] fmt.Println(s2) // [1, 2, 3] fmt.Println(cap(s2)) // 4 s3 := s2[:] fmt.Println(s3) // [1, 2, 3] fmt.Println(cap(s3)) // 4
Емкость s3 не может быть увеличена до более чем 4 (емкость s2), даже если базовая часть имеет 10 элементов и s1, s2 или s3 начинаются с индекса 1.
Правило из предыдущего раздела (high ≤ len (input)) имеет одно исключение. Когда операнд является срезом, тогда high фактически не может быть больше, чем cap (input) (площадка):
numbers := [10]int{0,1,2,3,4,5,6,7,8,9} s1 := numbers[0:1] fmt.Println(s1) // [0] fmt.Println(len(s1)) // 1 fmt.Println(cap(s1)) // 10 s2 := numbers[0:5] fmt.Println(s2) // [0, 1, 2, 3, 4] fmt.Println(cap(s1)) // 10
Когда он достигает значения max, существуют два дополнительных правила относительно его значения (игровая площадка):
- высокий ≤ макс
- max ≤ cap (ввод)
numbers := [10]int{0,1,2,3,4,5,6,7,8,9} s1 := numbers[0:1] s2 := numbers[0:5:11] // invalid slice index 11 (out of bounds for 10-element array) fmt.Println(s1, s2)
В выражении полного среза необязателен только индекс low (площадка):
numbers := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s := numbers[:4:6] fmt.Println(s) // [0, 1, 2, 3] fmt.Println(cap(s)) // 6
Пропуск high не допускается (детская площадка):
numbers := [10]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s1 := numbers[:4:6] s2 := s1[::5] fmt.Println(s2) fmt.Println(cap(s2))
Такой код даже не скомпилируется - middle index required in 3-index slice
.
Нажмите ❤ ниже, чтобы помочь другим узнать эту историю. Если вы хотите получать обновления о новых сообщениях, подписывайтесь на меня.