Golang

数组,切片

2019-04-25  本文已影响6人  ifcoder

数组

创建方式

提起切片,我们必须要先了解数组,数组的类型名是[n]elementType,n代表数组长度,elementType是数组元素类型。数组的定义方式如下:

// var elementName [n]elementType
var array [2]int    // [0 0];声明一个含有两个int类型的数组,因为未初始化,所以元素都为默认值0
array2:=[...]int{1,2,3} // 可以不指定数组长度,但必须指定"...",然后编译器自动根据字面量初始化列表推导数组长度。

数组常见创建方式

arr1:=[3]int{1,2,3} // [1 2 3]
arr2:=[...]int{1,2,3}   // [1 2 3]
arr3:=[3]int{1:1,2:2} // [0 1 2]
arr4:=[...]int{3:3,5:5} // [0 0 0 3 0 5]

数组特点

遍历数组

a:=[2]int{1,2}
// idx是索引,v是值
for idx,v:=range a{
   fmt.Println(idx,v)
}
for i:=0;i<len(a);i++{
   fmt.Println(i,a[i])
}

切片

因为数组的长度固定,而且是值拷贝,所以限制了数组的使用场景。此时切片(slice)应运而生,它是一种变长数组,它是一种引用类型(map、channel也是引用类型)。

slice的底层如下:

type slice struct {
    array unsafe.Pointer    // 指向底层数组的指针
    len   int                           // 切片的元素数量
    cap   int                           // 底层数组容量
}

创建方式

常见操作

s:=[]int{1,2}
fmt.Println(len(s)) // len=2,返回切片长度

fmt.Println(cap(s)) // cap=2,返回切片容量

s=append(s,3)               // 向s追加元素;切片元素:[1,2,3];len=3,cap=4,切片长度超过原来的容量,自动扩容,容量扩大为原来的两倍

s1:=[]int{4,5}
s=append(s,s1...)   // 向s追加切片
fmt.Println(s)  // [1 2 3 4 5]

s=append(s,7,8) // 向切片追加多个元素
fmt.Println(s)  // [1 2 3 4 5 7 8]

c:=[]int{1,2,3}
b:=make([]int,2)    // [0 0]
copy(b,c)   //只会复制长度较小的,第一个参数是目的切片,第二个参数是源切片
fmt.Println(b) // [1 2]

c1:=[]int{1,2,3}
b1:=make([]int,5)   // [0 0 0 0 0]
copy(b1,c1) 
fmt.Println(b1) // [1 2 3 0 0]

Tips:

  1. 当切片的长度超过容量cap的时候,切片会进行扩容,cap直接扩大为原来的2倍。

  2. append函数定义如下,第一个参数表示向哪个切片追加元素,后面的是可变参数,可以添加多个参数,也可以添加一个切片,当第二个参数是切片时,需要在切片后面添加三个点来表示引用切片中所有元素"..."

    注意:可变参数可以是单个元素,也可以是一个切片…,但不能两者同时出现。

func append(slice []Type, elems ...Type) []Type
    s:=[]int{1,2}
            
    s1:=[]int{4,5}
    
    // s=append(s,1,s1...) // 报错

    // s=append(s,s1...,1)  // 报错

字符串和切片相互转换

str:="深夜幽魂"
a:=[]byte(str)  // [230 183 177 229 164 156 229 185 189 233 173 130]
b:=[]rune(str)  // [28145 22812 24189 39746]

c:=[]byte{230,183,177,229,164,156,229,185,189,233,173,130}
fmt.Println(string(c))  // 深夜幽魂
d:=[]rune{28145,22812,24189,39746}
fmt.Println(string(d))  // 深夜幽魂

Tips:字符串转切片的时候需要注意,尤其当字符串内容很大的时候,因为每一次都要复制内容

刁钻难点

  1. 通过var b []int创建切片,该切片底层array指针不指向任何数组(也就是array的值为nil),len、cap都是0;但通过a:=[]int{}这种方式创建的切片,虽然len、cap也都是0,但是底层array是开辟了空间的,不为nil
a:=[]int{}
var b []int
fmt.Println(a,a==nil,len(a),cap(a)) // [] false 0 0
fmt.Println(b,b==nil,len(b),cap(b)) // [] true 0 0
  1. 通过array[s:e]创建切片的时候,其实还可以这样array[s:e:c],c的最大值是数组的长度或者切片的容量的最大值。e-s是该切片的长度,c-s是该切片的容量

    a:=[]int{1,2}
    b:=a[0:1:2]
    fmt.Println(b,len(b),cap(b)) // [1] 1 2
    
上一篇 下一篇

猜你喜欢

热点阅读