#go
#Вперед
Вопрос:
Я просматриваю обзор Go и хотел бы знать следующее:
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 %vn", 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?
Комментарии:
Ответ №1:
Фрагменты 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 = amp;s[:cap(s)][0]
}
fmt.Printf("ptr=%p len=%d cap=%d %vn", 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]
Посмотрите, как ваши операции среза регулируют указатель, длину и емкость. Фрагмент — это просто вид или окно в базовый массив.
Ссылки:
Ответ №2:
Фрагмент имеет буфер под обложками. Емкость — это размер этого буфера. Удаление элементов с конца не изменяет размер буфера.
Вы создаете новый фрагмент из существующего фрагмента, но начинаете индекс нового фрагмента с 2. Новый фрагмент по-прежнему указывает на тот же базовый буфер (но смещен на 2). Таким образом, размер буфера (и емкость) для этого нового фрагмента на 2 меньше.
Емкость имеет смысл, когда вы видите, как работает append . Append пытается повторно использовать тот же базовый буфер — но если емкость заполнена, выполняется перераспределение и копирование.