go语言学习(四):数组和切片

mb5fed72b60246f · · 429 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

在go语言中,数组和切片都是集合类型,他们都是用来存储同一种类型的元素。

1.数组类型的长度是固定的,而切片类型的长度是可变长的。如下面代码声明一个长度为5的数组s1和长度为5的切片s2,

s1 := [5]int{1,2,3,4,5}
s2 := []int{1,2,3,4,5}

但是s1是不可变的,而s2是可变的,可以增加元素,长度随着元素数量而增长。因此数组是一个值类型,而切片是一个引用类型。

2.切片的底层是一个数组,如下面代码:s3是s4的底层数组,

s3 := []int{1, 2, 3, 4, 5, 6, 7, 8}
s4 := s3[3:6]
fmt.Printf("The length of s4: %d\n", len(s4))
fmt.Printf("The capacity of s4: %d\n", cap(s4))
fmt.Printf("The value of s4: %d\n", s4)

上面代码输出如下:

The length of s4: 3
The capacity of s4: 5
The value of s4: [4 5 6]

因为切片S4取值从数组S3的下标4开始到下标6(不包含),所以长度是3,容量是5

3.切片是可以扩容的,往切片中增加元素时,当切片容量不够时,切片会进行扩容。

如果扩容前切片容量小于1024,那扩展为原容量的2倍。

如果扩容前切片容量大于等于1024,那扩展为原容量的1.25倍,如果还不够,会再次扩展为原来的1.25倍。

如果追加元素太多,扩展为2倍还不够,会直接扩展为新的长度。

// 示例1。
  s6 := make([]int, 0)
  fmt.Printf("The capacity of s6: %d\n", cap(s6))
  for i := 1; i <= 5; i++ {
    s6 = append(s6, i)
    fmt.Printf("s6(%d): len: %d, cap: %d\n", i, len(s6), cap(s6))
  }
  fmt.Println()

  // 示例2。
  s7 := make([]int, 1024)
  fmt.Printf("The capacity of s7: %d\n", cap(s7))
  s7e1 := append(s7, make([]int, 200)...)
  fmt.Printf("s7e1: len: %d, cap: %d\n", len(s7e1), cap(s7e1))
  s7e2 := append(s7, make([]int, 400)...)
  fmt.Printf("s7e2: len: %d, cap: %d\n", len(s7e2), cap(s7e2))
  s7e3 := append(s7, make([]int, 600)...)
  fmt.Printf("s7e3: len: %d, cap: %d\n", len(s7e3), cap(s7e3))
  fmt.Println()

  // 示例3。
  s8 := make([]int, 10)
  fmt.Printf("The capacity of s8: %d\n", cap(s8))
  s8a := append(s8, make([]int, 11)...)
  fmt.Printf("s8a: len: %d, cap: %d\n", len(s8a), cap(s8a))
  s8b := append(s8a, make([]int, 23)...)
  fmt.Printf("s8b: len: %d, cap: %d\n", len(s8b), cap(s8b))
  s8c := append(s8b, make([]int, 45)...)
  fmt.Printf("s8c: len: %d, cap: %d\n", len(s8c), cap(s8c))

  s1 := [5]string{"a","b","c","d","e"}
  fmt.Printf("S1:%s\n", s1)
  s2 := s1[3:5]
  fmt.Printf("S2:%s\n", s2)

上面代码的输出如下:

The capacity of s6: 0
s6(1): len: 1, cap: 1
s6(2): len: 2, cap: 2
s6(3): len: 3, cap: 4
s6(4): len: 4, cap: 4
s6(5): len: 5, cap: 8

The capacity of s7: 1024
s7e1: len: 1224, cap: 1280
s7e2: len: 1424, cap: 1696
s7e3: len: 1624, cap: 2048

The capacity of s8: 10
s8a: len: 21, cap: 22
s8b: len: 44, cap: 44
s8c: len: 89, cap: 96

因为操作系统内存对齐的原因,扩容后的切片并不能恰好成为原切片的2倍或1.25倍

4.当切片扩容时,原切片和底层数据并没有被替换,而且生成了一个新的底层数组和切片。

当切片无需扩容时,append函数会返回一个指向原底层数组的新切片,但是当需要扩容时,append函数返回一个指向新底层数组的新切片。

// 示例1。
  a1 := [7]int{1, 2, 3, 4, 5, 6, 7}
  fmt.Printf("a1: %v (len: %d, cap: %d)\n", a1, len(a1), cap(a1))
  s9 := a1[1:4]
  //s9[0] = 1
  fmt.Printf("s9: %v (len: %d, cap: %d)\n", s9, len(s9), cap(s9))
  for i := 1; i <= 5; i++ {
    s9 = append(s9, i)
    fmt.Printf("s9(%d): %v (len: %d, cap: %d)\n", i, s9, len(s9), cap(s9))
  }
  fmt.Printf("a1: %v (len: %d, cap: %d)\n", a1, len(a1), cap(a1))
  fmt.Println()

上面代码输出:

a1: [1 2 3 4 5 6 7] (len: 7, cap: 7)
s9: [2 3 4] (len: 3, cap: 6)
s9(1): [2 3 4 1] (len: 4, cap: 6)
s9(2): [2 3 4 1 2] (len: 5, cap: 6)
s9(3): [2 3 4 1 2 3] (len: 6, cap: 6)
s9(4): [2 3 4 1 2 3 4] (len: 7, cap: 12)
s9(5): [2 3 4 1 2 3 4 5] (len: 8, cap: 12)
a1: [1 2 3 4 1 2 3] (len: 7, cap: 7)

参考:极客时间


有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:mb5fed72b60246f

查看原文:go语言学习(四):数组和切片

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

429 次点击  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传