Повторное нарезание ломтиков в Голанге
Я недавно выбрал язык Go, и теперь меня смущает следующий код:
package main
import "fmt"
func main() {
a := make([]int, 5)
printSlice("a", a)
b := make([]int, 0, 5)
printSlice("b", b)
c := b[:2]
printSlice("c", c)
d := c[2:5]
printSlice("d", d)
}
func printSlice(s string, x []int) {
fmt.Printf("%s len=%d cap=%d %v\n",
s, len(x), cap(x), x)
}
И результат:
a len=5 cap=5 [0 0 0 0 0]
b len=0 cap=5 []
c len=2 cap=5 [0 0] //why the capacity of c not 2 but 5 instead
d len=3 cap=3 [0 0 0]
Ответы
Ответ 1
c
- это срез, взятый из массива b
. Это не копия, а просто окно над двумя первыми элементами b
.
Поскольку b
имеет емкость 5, c
может быть расширен, чтобы занять 3 других места (на самом деле он создает новый срез, но в одном и том же месте в памяти).
Максимальная емкость среза - это емкость базового массива за вычетом позиции начала среза в массиве:
array : [0 0 0 0 0 0 0 0 0 0 0 0]
array : <---- capacity --->
slice : [0 0 0 0]
slice : <---- capacity --->
Возможно, эта программа сделает более понятным, что c и d - это просто окна над b:
func main() {
b := make([]int, 0, 5)
c := b[:2]
d := c[1:5] // this is equivalent to d := b[1:5]
d[0] = 1
printSlice("c", c)
printSlice("d", d)
}
Выход:
c len=2 cap=5 [0 1] // modifying d has modified c
d len=4 cap=4 [1 0 0 0]
Ответ 2
Обратите внимание, что в go 1.2 (Q4 2013, теперь доступна 1.2rc1), вы можете связать с срезом емкость собственного (вместо мощности, выводимой из базового массива).
См. "трехиндексные фрагменты и проект.
Операция среза создает новый срез, описывая непрерывный раздел уже созданного массива или среза:
var array [10]int
slice := array[2:4]
Емкость среза - это максимальное количество элементов, которые может удерживать срез, даже после повторного выделения; он отражает размер базового массива.
В этом примере емкость переменной среза равна 8.
(емкость базового массива минус позиция начала среза в массиве)
array : [0 0 0 0 0 0 0 0 0 0]
array : <---- capacity --->
slice : [0 0]
slice : <-- capacity --> 8 (10-2)
Перейти 1.2 добавляет новый синтаксис, позволяющий операции разрезания указать емкость, а также длину.
Второй двоеточие вводит значение емкости, которое должно быть меньше или равно емкости среза источника или массива, скорректированного на начало координат.
Например,
slice = array[2:4:6]
array : [0 0 0 0 0 0 0 0 0 0]
array : <---- capacity ---> 10
slice : [0 0]
slice : <- cap-> 4 (6-2)
устанавливает, чтобы срез имел ту же длину, что и в предыдущем примере, но его емкость теперь составляет всего 4 элемента (6-2).
Невозможно использовать это новое значение среза для доступа к последним двум элементам исходного массива.
Основной аргумент - дать программистам больше контроля над append
.
a[i : j : k]
Этот срез имеет:
- начинающиеся с 0
- длина равна
j - i
- емкость равна
k - i
Паника оценки, если i <= j <= k <= cap(a)
не соответствует true.