Почему cap не печатает длину базового массива? - PullRequest
0 голосов
/ 28 июня 2019

Я читаю A Tour of GO, в разделе Длина и емкость среза , я запустил пример:

package main

import "fmt"

func main() {
    s := []int{2, 3, 5, 7, 11, 13}
    printSlice(s)

    // Slice the slice to give it zero length.
    s = s[:0]
    printSlice(s)

    // Extend its length.
    s = s[:4]
    printSlice(s)

    // Drop its first two values.
    s = s[2:]
    printSlice(s)
}

func printSlice(s []int) {
    fmt.Printf("len=%d cap=%d %v\n", len(s), cap(s), s)
}

Когда я собираю приложение и запускаю его, оно печатается так:

len=6 cap=6 [2 3 5 7 11 13]
len=0 cap=6 []
len=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]

В Go документах, cap - это длина базового массива, почему его значение не равно 6?

Ответы [ 2 ]

9 голосов
/ 28 июня 2019

В Go документах, cap - это длина базового массива, почему его значение не равно 6?

Поскольку емкость равна , а не размер базового массива (могут быть особые случаи, когда они равны, но в целом они не равны). Когда срез создается путем нарезки резервного массива, используя 0 для низкого индекса (или опуская его) и длину массива для высокого индекса (или опуская его), тогда да, емкость будет равна массиву длина.

Спецификация: длина и вместимость:

Емкость слайса - это количество элементов, для которых есть место, выделенное в базовом массиве.

Таким образом, емкость начинается с первого элемента среза, и если он не совпадает с первым элементом резервного массива, они не будут равны. Об этом прямо говорится на странице Tour , на которую вы ссылаетесь:

Емкость слайса - это количество элементов в базовом массиве, считая от первого элемента в слайсе .

Существует также полное выражение среза , которое имеет вид:

a[low : high : max]

Там, где вы можете контролировать емкость результирующего среза, вы можете ограничить, насколько дальнейшее срезание может расширить срез. Индекс max может указывать на элемент перед последним элементом массива.

См. Этот пример:

a := [10]int{}

s := a[:] // len=10, cap=10
fmt.Printf("len=%d, cap=%d\n", len(s), cap(s))

s = a[2:] // len=8, cap=8
fmt.Printf("len=%d, cap=%d\n", len(s), cap(s))

s = a[2:7] // len=5, cap=8
fmt.Printf("len=%d, cap=%d\n", len(s), cap(s))

s = a[2:7:8] // len=5, cap=6
fmt.Printf("len=%d, cap=%d\n", len(s), cap(s))

Выходы (попробуйте на Go Playground ):

len=10, cap=10
len=8, cap=8
len=5, cap=8
len=5, cap=6
1 голос
/ 28 июня 2019

Когда вы отбрасываете два первых значения, вы остаетесь только с последними 4 оставшимися элементами в базовом массиве.

[2 3 5 7 11 13]

Когда вы делаете s = [:0], срез будет иметьдлина 0 и крышка 6: []2 3 5 7 11 13

Когда вы делаете s = [:4] срез будет иметь длину 4 и крышку 6: [2 3 5 7] 11 13

Когда вы делаете s = [2:] срез будет иметьдлина 2 и ограничение 4: 2 3 [5 7] 11 13

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

...