Почему емкость среза изменяется, когда вы отбрасываете первые n элементов, а не последние n элементов? - PullRequest
2 голосов
/ 20 марта 2019

Я прохожу тур по Го и хотел знать следующее:

package main

import "fmt"

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

    // Drop its last two values
    s = s[:len(s)-2]
    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=4 cap=6 [2 3 5 7]
len=2 cap=4 [5 7]

Почему емкость среза остается неизменной, когда вы отбрасываете 2 последних элемента, но изменяется, когда вы отбрасываете первые 2 элемента?

https://play.golang.org/p/ZNKwOYKDqOi

Ответы [ 2 ]

5 голосов
/ 20 марта 2019

Срезы Go реализованы в виде структуры:

src/runtime/slice.go:

type slice struct {
    array unsafe.Pointer
    len   int
    cap   int
}

Пересмотрите вашу printSlice функцию, чтобы показать указатель на базовый массив:

package main

import "fmt"

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

    // Drop its last two values
    s = s[:len(s)-2]
    printSlice(s)

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

func printSlice(s []int) {
    var ptr *int
    if cap(s) >= 1 {
        ptr = &s[:cap(s)][0]
    }
    fmt.Printf("ptr=%p len=%d cap=%d %v\n", ptr, len(s), cap(s), s)
}

Детская площадка: https://play.golang.org/p/pk3cpE_LsUV

Вывод:

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

Посмотрите, как ваши операции нарезки корректируют указатель, длину и емкость.Срез - это просто представление или окно в базовый массив.


Ссылки:

The Go Blog: Слайсы Go: использование и внутренние компоненты

Спецификация языка программирования Go:

0 голосов
/ 20 марта 2019

Срез имеет буфер под крышками. Емкость - это размер этого буфера. Удаление элементов с конца не меняет размер буфера.

Вы создаете новый срез из существующего среза, но начинаете индекс нового среза с 2. Новый срез все еще указывает на тот же базовый буфер (но смещен на 2). Таким образом, размер буфера (и емкость) для этого нового среза на 2 меньше.

Емкость имеет смысл, когда вы видите, как работает append. Append пытается повторно использовать тот же базовый буфер, но если емкость заполнена, выполняется перераспределение и копирование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...