where is the elements of slice will store if its size exceed the size of array?

huangapple go评论85阅读模式
英文:

where is the elements of slice will store if its size exceed the size of array?

问题

我从OrgArray数组创建了一个切片,代码如下:

orgArray := [3]string{"00", "01", "02"}
s := orgArray[:2]
s = append(s, "03")
s = append(s, "04")

其中's'是我在数组'orgArray'上建立的切片。

如果我打印出s和orgArray的大小:

fmt.Println(s) //[00 01 03 04]
fmt.Println(len(s), cap(s)) //4 6
fmt.Println(len(orgArray), cap(orgArray)) //3 3

len(s)是4,但len(orgArray)只有3,为什么?

在追加时,切片的额外元素存储在哪里?

英文:

I create a slice from the array OrgArray as follows

orgArray:=[3] string{"00","01","02"}
s := orgArray[:2]
s = append(s,"03")
s = append(s,"04")

Where 's' is my slice I built up on the array 'orgArray'

If I print the size of the s and orgArray

fmt.Println(s) //[00 01 03 04]
fmt.Println(len(s),cap(s)) //4 6
fmt.Println(len(orgArray),cap(orgArray)) //3 3

len(s) is 4 but len(orgArray) is only 3 why?

Where is the extra elements of slice is storing while appending?

答案1

得分: 5

《Go编程语言规范》

追加和复制切片

如果切片s的容量不足以容纳额外的值,append函数会分配一个新的足够大的底层数组,该数组既适合现有的切片元素,也适合额外的值。否则,append函数会重用底层数组。

有关append内置函数的详细信息,请阅读这篇博文:

《数组、切片(和字符串):'append'的机制》

还可以参考这个StackOverflow答案,其中说明了重新分配容量的计算方法:

append的复杂度

例如,

package main

import "fmt"

func main() {
    orgArray := [3]string{"00", "01", "02"}
    fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
    s := orgArray[:2]
    fmt.Println("       s:", &s[0], len(s), cap(s), s)
    s = append(s, "03")
    fmt.Println("       s:", &s[0], len(s), cap(s), s)
    s = append(s, "04")
    fmt.Println("       s:", &s[0], len(s), cap(s), s)
    fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
}

输出:

orgArray: 0x1052f2c0 3 [00 01 02]
       s: 0x1052f2c0 2 3 [00 01]
       s: 0x1052f2c0 3 3 [00 01 03]
       s: 0x1051a120 4 6 [00 01 03 04]
orgArray: 0x1052f2c0 3 [00 01 03]
英文:

> The Go Programming Language Specification
>
> Appending to and copying slices
>
> If the capacity of s is not large enough to fit the additional values,
> append allocates a new, sufficiently large underlying array that fits
> both the existing slice elements and the additional values. Otherwise,
> append re-uses the underlying array.

For additional details on how the append built-in function works, read this blog post:

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

Also, see this StackOverflow answer, which illustrates the reallocation capacity calculation:

append complexity

For example,

package main

import "fmt"

func main() {
	orgArray := [3]string{"00", "01", "02"}
	fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
	s := orgArray[:2]
	fmt.Println("       s:", &s[0], len(s), cap(s), s)
	s = append(s, "03")
	fmt.Println("       s:", &s[0], len(s), cap(s), s)
	s = append(s, "04")
	fmt.Println("       s:", &s[0], len(s), cap(s), s)
	fmt.Println("orgArray:", &orgArray[0], len(orgArray), orgArray)
}

Output:

orgArray: 0x1052f2c0 3 [00 01 02]
       s: 0x1052f2c0 2 3 [00 01]
       s: 0x1052f2c0 3 3 [00 01 03]
       s: 0x1051a120 4 6 [00 01 03 04]
orgArray: 0x1052f2c0 3 [00 01 03]

答案2

得分: 2

slice的结构如下:

struct Slice {
    byte* array; // 实际数据
    uintgo len; // 元素数量
    uintgo cap; // 分配的元素数量
};

而在你的示例中,解释如下:

orgArray := [3]string{"00", "01", "02"}
s := orgArray[:2]
fmt.Println(len(s), cap(s))  //2,3 s是指向orgArray的指针
s = append(s, "03")
fmt.Println(len(s), cap(s))  //3,3 cap足够。s仍然指向orgArray
s = append(s, "04")
fmt.Println(len(s), cap(s))  //4,6 cap不足。重新生成数组,然后s指向新的数组
英文:

slice's struct is like this:

struct Slice
{ // must not move anything
 byte* array; // actual data
 uintgo len; // number of elements
 uintgo cap; // allocated number of elements
};

while in your example. explain as follow:

orgArray := [3]string{"00", "01", "02"}
s := orgArray[:2]
fmt.Println(len(s),cap(s))  //2,3 s is pointer to orgArray
s = append(s, "03")
fmt.Println(len(s),cap(s))  //3,3 cap is enough. s is pointer to orgArray
s = append(s, "04")
fmt.Println(len(s),cap(s))  //4,6 cap is not enough. regenerate array. then s point to the new array.

答案3

得分: 1

s := orgArray[:2]

由于你从原始切片中取出两个元素,然后再追加两个元素,长度变为4。你可以在这里看到这四个元素:

fmt.Println(s) //[00 01 03 04]

如果你想知道为什么容量是6,那是因为容量是以2的幂增加的。所以,如果你有一个容量为4的切片,并追加5个元素,容量将变为8。这与在追加发生时尝试重新分配切片的内存有关。

英文:
s := orgArray[:2]

Since you take two elements from the original slice and then append two more the length becomes 4. You can see the four elements here:

fmt.Println(s) //[00 01 03 04]

If you wonder why the capacity is 6 it's because capacity is increased in power of 2. So if you have a slice with capacity 4 and append 5 elements the capacity will become 8. It is related to trying to re-allocate the memory for the slice that often when append occurs.

huangapple
  • 本文由 发表于 2014年3月20日 19:49:43
  • 转载请务必保留本文链接:https://go.coder-hub.com/22532053.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定