2015-01-27 8 views
1

Вместимость параметр при создании slice в Go не имеет для меня большого смысла. Например,Ломтики в Go: почему он позволяет добавлять больше, чем позволяет емкость?

aSlice := make([]int, 2, 2) //a new slice with length and cap both set to 2 
aSlice = append(aSlice, 1, 2, 3, 4, 5) //append integers 1 through 5 
fmt.Println("aSlice is: ", aSlice) //output [0, 0, 1, 2, 3, 4, 5] 

Если срез позволяет вставлять больше элементов, чем емкость позволяет, почему нам нужно установить его в функции макияжа()?

+0

Обратите внимание, что вы не имеете права устанавливать его в марку. Существует [форма с двумя аргументами] (http://golang.org/ref/spec#Making_slices_maps_and_channels) 'make ([] T, n)', чтобы дать вам фрагмент T длины n. – dutchie

ответ

11

Функция builtin append() использует указанный фрагмент для добавления элементов в , если имеет достаточно большую емкость для размещения указанных элементов.

Но если пройденный срез недостаточно велик, он выделяет новый, достаточно большой фрагмент, копирует элементы из пройденного фрагмента в новый срез и добавляет элементы к этому новому фрагменту. И возвращает этот новый фрагмент. Цитирование из документации append():

Добавление встроенной функции добавляет элементы в конец среза. Если он имеет достаточную пропускную способность, место назначения перераспределяется для размещения новых элементов. Если это не так, будет выделен новый базовый массив. Append возвращает обновленный срез. Поэтому необходимо, чтобы сохранить результат Append, часто в переменном держа сам срез:

При изготовлении ломтика с make, если длиной и емкость одинакова, емкость может быть опущена, в этом случае она по умолчанию для заданной длины:

// These 2 declarations are equivalent: 
s := make([]int, 2, 2) 
s := make([]int, 2) 

отметить также, что append() дописывает элементы после последнего элемента среза. И выше ломтиков уже len(s) == 2 сразу после заявления, так что если вы добавите даже только один элемент к нему, это приведет к перераспределению, как показано в следующем примере:

s := make([]int, 2, 2) 
fmt.Println(s, len(s), cap(s)) 
s = append(s, 1) 
fmt.Println(s, len(s), cap(s)) 

Выход:

[0 0] 2 2 
[0 0 1] 3 4 

Таким образом, в ваш пример того, что вы должны сделать что-то вроде этого:

s := make([]int, 0, 10) // Create a slice with length=0 and capacity=10 
fmt.Println(s, len(s), cap(s)) 
s = append(s, 1) 
fmt.Println(s, len(s), cap(s)) 

Выход:

[] 0 10 
[1] 1 10 

Я рекомендую следующие статьи в блоге, если вы хотите, чтобы понять ломтики более подробно:

Go Slices: usage and internals

Arrays, slices (and strings): The mechanics of 'append'

+1

Большое спасибо за подробное объяснение, оцените его. – TonyGW

3

Это в основном оптимизация, и это не единственный идти, подобный структуры на других языках имеют это также.

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

Указывая емкость, среда выполнения выделяет то, что необходимо заранее, и избегает перераспределения.Однако, если вы заранее не знаете предполагаемую пропускную способность или меняете ее, вам не нужно ее устанавливать, а среда выполнения перераспределяет то, что необходимо, и увеличивает емкость.