Go 基础教程-7-slice

切片Slice

相关概念

  1. 其本身并不是数组,它指向底层的数组

  2. 作为变长数组的替代方案,可以关联底层数组的局部或全部
    为引用类型

  3. 可以直接创建或从底层数组获取生成

  4. 使用len()获取元素个数,cap()获取容量

  5. 一般使用make()创建

  6. 如果多个slice指向相同底层数组,其中一个的值改变会影响全部

    make([]T, len, cap)
    其中cap可以省略,则和len的值相同
    len表示存数的元素个数,cap表示容量

    7.  切片的长度不会超过它的容量(否则报错)

切片长度使用汇总

func main(){
  a := [10]int{1,2,3,4,5,6,7,8,9,10}
  fmt.Println(a)
  //从第5个索引开始截取
  s1 = a[5:]
  s3 = a[5:len(a)]
  //从索引0截取,遇到索引为5停下来(不包含索引为5)
  s0 = a[:5]
  //从第5个开始截取,遇到索引为10停下来(不包含索引10)
  s2 = a[5:10]
  //取完整数组
  s1 = [:]

}

Slice与底层数组的对应关系

image-20190922190754601

实例1:
package main
import "fmt"

func main() {
    var s1 []int
    fmt.Println(s1)
}
//[]
实例2:
package main

import "fmt"

func main() {
    a := [10]int{}
    fmt.Println(a)
    s1 := a[5:10]//5:10 表示从索引5开始,不包含索引10结尾
    fmt.Println(s1)
}
//[0 0 0 0 0 0 0 0 0 0]
//[0 0 0 0]
s1 := a[5:]//5:0 表示从5开始取到0
fmt.Println(s1)
//[0 0 0 0 0 0 0 0 0 0]
//[0 0 0 0 0]
s1 := a[:5]//5:0 表示不包含索引为5
fmt.Println(s1)
实例3:

s1 = make([]int,长度,初始容量)

  • 不设置初始容量,默认为指定长度的容量
  • 当长度在初始容量内,不需要重新分配内存
  • 当长度超过初始容量,会分配给2倍初始容量的内存(分配内存很耗性能)

s1 = make([]int,10,10),容量被占满,如果再给s1增加元素,容量自动翻倍为20,此时s1 = make([]int,11,20)

package main

import "fmt"

func main() {
    s1 := make([]int,3,10)
    fmt.Println(len(s1),cap(s1))
}
//3 10
//len长度、cap容量

s1 := make([]int,3)
fmt.Println(len(s1),cap(s1))
//3 3

实例4:
package main

import "fmt"

func main() {
    //s1 := make([]int,3)
    //fmt.Println(len(s1),cap(s1))

    a := []byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sa := a[2:4]
    sb := a[2:5]
    sc := a[:]//表示完整的数组
    fmt.Println(sa)
    fmt.Println(string(sa))
    fmt.Println(string(sb))
}


//[99 100]
//cd
//cde
实例5:

Reslice

Reslice时索引以被slice的切片为准
索引不可以超过被slice的切片的容量cap()值
索引越界不会导致底层数组的重新分配而是引发错误

package main

import "fmt"

func main() {
    //s1 := make([]int,3)
    //fmt.Println(len(s1),cap(s1))

    a := []byte{'a','b','c','d','e','f','g','h','i','j','k'}
    sa := a[2:4]
    fmt.Println(len(sa),cap(sa))
    sb := a[2:5]
    fmt.Println(sa)
    fmt.Println(string(sa))
    fmt.Println(string(sb))
}
//2 9
//[99 100]
//cd
//cde

越界

package main

import "fmt"

func main() {
    //s1 := make([]int,3)
    //fmt.Println(len(s1),cap(s1))

    a := []byte{'a','b','c','d','e','f','g','h','i','j','k'}
  //c、d
    sa := a[2:4]
  //3、9 容量为9
  //体现:Reslice时索引以被slice的切片为准
    fmt.Println(len(sa),cap(sa))
  //c、d、e
    sb := a[2:5]
    fmt.Println(sa)
    fmt.Println(string(sa))
    fmt.Println(string(sb))
  //索引不可以超过被slice的切片的容量cap()值
    sc := sa[9:11]
    println(string(sc)) 
}

//2 9
//[99 100]
//cd
//cde
//panic: runtime error: slice bounds out of range

goroutine 1 [running]:
main.main()
    /Users/care/go/src/awesomeProject/slice2.go:16 +0x2ba
exit status 2

Append

可以在slice尾部追加元素
可以将一个slice追加在另一个slice尾部
如果最终长度未超过追加到slice的容量则返回原始slice的内存和新的slice
如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据

实例1:

可以在slice尾部追加元素
可以将一个slice追加在另一个slice尾部
如果最终长度未超过追加到slice的容量则返回原始slice的内存和新的slice

package main

import "fmt"

func main() {
    s1 := make([]int,3,6)
    fmt.Printf("%p\n",s1)
    s1 = append(s1,1,2,3)
    fmt.Printf("%v %p\n",s1,s1)
}

//0xc00001a090
//[0 0 0 1 2 3] 0xc00001a090

//如果超过追加到的slice的容量则将重新分配数组并拷贝原始数据

func main() {
    s1 := make([]int,3,6)
    fmt.Printf("%p\n",s1)
    s1 = append(s1,1,2,3)
    fmt.Printf("%v %p\n",s1,s1)
    s1 = append(s1,1,2,3)
    fmt.Printf("%v %p\n",s1,s1)
}
//0xc00001a0f0
//[0 0 0 1 2 3] 0xc00001a0f0
//[0 0 0 1 2 3 1 2 3] 0xc000086000

实例2:

slice指向一个底层数组,一个改变,另一个也跟着改变

package main
import "fmt"
func main() {
    a:= []int{1,2,3,4,5,6}
    s1 := a[2:5]
    s2 := a[1:3]
    fmt.Println(s1,s2)
    s1[0] = 9
    fmt.Println(s1,s2)
}
//slice指向一个底层数组,一个改变,另一个也跟着改变
//[3 4 5] [2 3]
//[9 4 5] [2 9]

func main() {
    a:= []int{1,2,3,4,5,6}
    s1 := a[2:5]
    s2 := a[1:3]
    fmt.Println(s1,s2)
    s2 = append(s2,1,2,3,4,5,6,7,8,9)
    s1[0] = 9
    fmt.Println(s1,s2)
}
//原先s1和s2底层共同指向数组a,s2数组超过长度重新分配内存,所以改变s1的值,s2不受影响
//[3 4 5] [2 3]
//[9 4 5] [2 3 1 2 3 4 5 6 7 8 9]

Copy

copy(s1,s2) 把s2复制到s1

实例:

package main

import "fmt"
//s2复制到s1
func main() {
    s1 := []int{1,2,3,4,5,6}
    s2 := []int{7,8,9}
    //copy(s1,s2)
    fmt.Println(s1)
    //把s2复制到s1
    //[7 8 9 4 5 6]
}

//s1复制到s2
func main() {
    s1 := []int{1,2,3,4,5,6}
    s2 := []int{7,8,9}
    copy(s2,s1)
    fmt.Println(s2)
    //把s1复制到s2
    //[1 2 3]
}

cpoy一部分

实例:

package main

import "fmt"

func main() {
    s1 := []int{1,2,3,4,5,6}
    s2 := []int{7,8,9,10,1,1,1,1,1}
    copy(s2,s1[1:3])
    fmt.Println(s2)
}
//[2 3 9 10 1 1 1 1 1]
copy(s2[2:4],s1[1:3])
fmt.Println(s2)
//[7,8,2,3,1,1,1,1,1]

课堂作业

如何将一个slice指向一个完整的底层数组,而不是底层数组的一部分?

s2 := s1
s2 := s1[:]
go
本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!