Golang(4)

切片

原数组存在很多的不足:

  1. 在方法中申明数组,需要声明长度,故该函数只能接收该长度的数据,其他的都不支持
  2. 当原数组只能支持指定长度的容量,当容量已满的情况,就不能往数组中添加元素,例如下代码
  1. //1
  2. func arraySum(x [3]int) int{
  3. sum := 0
  4. for _, v := range x{
  5. sum = sum + v
  6. }
  7. return sum
  8. }
  9. //2
  10. a := [3]int{1, 2, 3}

特点

  1. 切片基于数组的再封装
  2. 可变长度的序列
  3. 支持自动扩容
  4. 为一个引用类型
  5. 内部包括长度、容量、地址的数据结构

声明

var name []T
package main

import "fmt"

func main() {
    var a [] string
    var b =  []int{1,2,3}
    var c = []bool{false,true}

    fmt.Println(a)
    fmt.Println(b)
    fmt.Println(c)
}

切片表达式

package main

import "fmt"

func main() {
    a := [7]int{1, 2, 3, 4, 5, 6, 7}
    s := a[4:6] // s := a[low:high]
  //s:[5 6] len(s):2 cap(s):3
    fmt.Printf("s:%v len(s):%v cap(s):%v\n", s, len(s), cap(s))
  //s:[1 2 3 4 5 6 7] len(s):7 cap(s):7
    fmt.Printf("s:%v len(s):%v cap(s):%v\n", a, len(a), cap(a))
}

切片的cap()值可以理解为,切片总长度-左指针位置

使用make()函数构造切片

以上都是基于数组的基础上,进行切片构造操作

还可以通过make函数来动态的进行切片操作

make([]T,size,cap)
//[]T 为元素类型
//size 为元素数量
//cap 为数组容量

切片的原理

切片本质所涵盖的信息为三个:数组指针、长度、容量

image.png

判断切片是否为空的方式

判断是否为空的方式:使用len(s) == 0的方式。

错误的方式: s == nil

原因,切片有两种情况:

  1. 可能s被初始化后,s != nil,但是len(s)和cap(s)均为0
  2. 可能s未被初始化,s == nil,len(s)和cap(s)均为0
package main

import "fmt"

func main() {
    var a []int
    b := []int{}
    c := make([]int,0,0)

  //0       0       true
    fmt.Printf("%d\t%d\t%v\n", len(a) , cap(a) ,a==nil)
  //0       0       false
    fmt.Printf("%d\t%d\t%v\n", len(b) , cap(b) ,b==nil)
  //0       0       false
    fmt.Printf("%d\t%d\t%v\n", len(c) , cap(c) ,c==nil)
}

拷贝赋值

拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容

package main

import "fmt"

func main() {
    s1 := []int{0,0,0}
    s2 := s1
    s2[0] = 100
  //[100 0 0]
    fmt.Println(s1)
  //[100 0 0]
    fmt.Println(s2)
}

切片添加元素append()方法

  1. 使用append方法时,切片无需初始化
  2. 此外append还可以添加多个元素或切片
package main
import "fmt"

func main() {
    var s []string
    s = append(s,"123","3456")
    fmt.Println(s)
    s1 := []string{"789"}
    s = append(s,s1...)
    fmt.Println(s)
}

切片扩容逻辑

newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
    newcap = cap
} else {
    if old.len < 1024 {
        newcap = doublecap
    } else {
        // Check 0 < newcap to detect overflow
        // and prevent an infinite loop.
        for 0 < newcap && newcap < cap {
            newcap += newcap / 4 
        }
        // Set newcap to the requested cap when
        // the newcap calculation overflowed.
        if newcap <= 0 {
            newcap = cap
        }
    }
}