【Go语言】切片类型

116 阅读10分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

切片的初始化分析

1. nil切片初始化

结构:

var 切片名 []元素类型

结构分解:img

解析:在Go里,nil 切片是很常见的创建切片的方法,Go不会为nil切片分配任何空间。需要注意的是,只有声明的切片才会产生nil切片,通过推导或数组截取的切片都是指针有指向的。且nil切片其长度和容量都为零。

2. 空切片初始化

使用内置函数make()初始化

结构:

切片名 := make([]元素类型,长度,容量)

结构写法:s := make([]type, len, cap)

释义:[]type表示切片元素类型,len表示切片长度,cap表示切片容量,len小于等于cap,其中len个元素会被初始化为对应type的零值。

结构分解: img

解析:通过make()函数也可以创建空函数,当我们只指定长度为0时,那么切片的容量和长度相等。但与nil切片不同的是,空切片指向的地址不是nil,指向的是一个内存地址,但是它也没有分配任何内存空间,即底层数组中包含0个元素。

扩展:在常见的切片初始方式中,make()函数也是较长用的方式,例如我们声明一个简单的容量为5,长度为7的整型切片。

 slice := make([]int, 5, 7)                                     //make函数初始化

终端输出: img

make函数初始化:切片是基于数组实现的,它的底层是数组,它自己本身非常小,可以理解为对底层数组的抽象。因为基于数组实现,所以它的底层的内存是连续非配的,效率非常高。它还有可以通过索引获得数据、可以迭代以及垃圾回收优化的好处。使用内置的make数时,需要传入一个参数,指定切片的长度,例子中我们使用的时 5 ,这时候切片的容量是 7 。当然我们也可以不单独指定切片的容量,这样的话切片的长度和容量是相等的。

3. 切片字面量初始化

结构:

切片名 := []元素类型{元素值1,元素值2}

结构分析:img

解析:切片字面量,这种方法和创建数组类似使用短类型声明(:=)(* 编译器会自动根据右值类型推断出左值的对应类型),不需要指定[]运算符里的值。初始的长度和容量会基于初始化时提供的元素的个数确定。*

切片的截取分析

1. 结构:

新切片名 := 原切片名[i:j]

结构分解:img

解析:切片的截取是基于现有的切片或者数组创建,使用[i:j]这样的操作符即可。它表示以i索引开始,到j索引结束,截取原数组或者切片,创建而成的新切片。新切片的值包含原切片的i索引,但是不包含j索引。需要注意的是,截取的切片还是存于原有切片上的,若原有切片有改动,新截取切片也是会有改变的。

2. 举例:初始化一个切片并同时截取数组切片的前三位元素,并在打印前替换当前首个元素。

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}            //切片字面值初始化
 // 切取数组索引下标0、1、2的内容
 arr2 := arr1[0:3]                                                 //切片截取
 arr2[0] = "知链科技"                                             //元素赋值
 fmt.Println(arr1) // [知链科技 区块链 人才 培养 摇篮]              //语句&表达式输出
 fmt.Println(arr2) // [知链科技 区块链 人才]

终端输出: img

结构解析:

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}          //切片字面值初始化      

切片字面值初始化:在此语句中通过短类型声明将切片声明并指定出切片类型,切片长度和切片容量,然后通过=(赋值运算符)将数据赋值切片元素的数据存储空间。

 // 切取数组索引下标0、1、2的内容
 arr2 := arr1[0:3]                                                 //切片截取         

切片截取:在此语句中通过短类型声明将切片声明并指定出切片类型,切片长度和切片容量,切片的截取是基于现有的切片或者数组创建,使用[i:j]这样的操作符即可。它表示以i索引开始,到j索引结束,截取原数组或者切片,创建而成的新切片。新切片的值包含原切片的i索引,但是不包含j索引。

 arr2[0] = "知链科技"                                              //元素赋值

元素赋值:依旧通过操作符[]来获取指定元素位置,再将新的元素数据赋值到切片元素的指定位置,形成新的切片,但需要注意的是这只修改了指定元素数据的过程量数据,底层的原始切片还是没有变化的。

 fmt.Println(arr1) // [知链科技 区块链 人才 培养 摇篮]              //语句&表达式输出
 fmt.Println(arr2) // [知链科技 区块链 人才]

语句&表达式输出:前期我们学习到fmt.Println(...) 可以将变量字符串输出到控制台,并在最后自动增加换行字符 \n。函数内语句依照main函数内依次执行。需要注意的是,如果只单纯的对指定切片元素进行重新赋值,并没有全局打印整个切片的情况下, 再次使用时则仍然是原始切片。当切片的数据被重新打印后,就完成了原始切片的数据元素的最终修改。

for range循环分析

1. 结构:

for index,value := range array{

循环体语句

}

释义:第一个返回值 index 是数值的下标。第二个value是在该下标位置的值。他们都是仅在 for 循环内部可见的局部变量。array为循环输出的元素数组。

结构分解: img

解析: for range 结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道(channel)。每个 rune 字符和索引在 for range 循环中是一一对应的,它能够自动根据 UTF-8 规则识别 Unicode 编码的字符。Go语言和其他语言类似,可以通过 for range 的组合,对切片元素进行遍历,遍历时,index 和 value分别代表字符串的索引和字符串中的每一个字符。

2. 举例: 通过go语言特有的for range 循环打印截取一个切片打印输出:

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}           //数组字面值初始化   
 arr2 := arr1[0:3]                                               //切片截取
 for index, value := range arr2 {                                 //for range循环
    fmt.Println(index, value)
 }

终端输出:img

结构解析:

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}           //数组字面值初始化  

数组字面值初始化:在此语句中通过短类型声明将数组声明并指定出数组类型和数组长度(即数组元素的数据存储的内存空间),然后通过=(赋值运算符)将数据赋值给数组元素的数据存储空间。

arr2 := arr1[0:3]                                               //切片截取

切片截取:在此语句中通过短类型声明将切片声明并指定出切片类型,切片长度和切片容量,切片的截取是基于现有的切片或者数组创建,使用[i:j]这样的操作符即可。它表示以i索引开始,到j索引结束,截取原数组或者切片,创建而成的新切片。新切片的值包含原切片的i索引,但是不包含j索引。

for index, value := range arr2 {                                  //for range循环
   fmt.Println(index, value)
}

for range* 循环:for range 结构是Go语言特有的一种的迭代结构,在许多情况下都非常有用,for range 可以遍历数组、切片、字符串、map 及通道(channel)。 在for range 循环打印的过程中依次将切片arr2中的元素依据下标索引依次打印输出元素内存所储存的数据。*

3. 思考:元素打印时依据索引去打印相应的储存数据,那我们能否只获得我们想要的元素值,而省略索引值?

依据上例试运行:

for _, value := range arr2 {                                   //for range省略循环
   fmt.Println(value)
}

终端输出:img

以此,我们可以得知:* 在go语言中,我们可以通过 “_”空白标识符来代替索引。*

切片的传统循环分析

切片的传统循环分析

1. 结构:

for init; condition; post {

循环体语句

}

释义:init: 一般为赋值表达式,给控制变量赋初值;condition: 关系表达式或逻辑表达式,循环控制条件;post: 一般为赋值表达式,给控制变量增量或减量。

结构分解: img

解析:切片的常规遍历,通过for循环来实现遍历过程,先对表达式 init 赋初值;再判别赋值表达式 init 是否满足给定 condition 条件,若其值为真,满足循环条件,则执行循环体内语句,然后执行 post,进入第二次循环,再判别 condition;否则判断 condition 的值为假,不满足条件,就终止for循环,执行循环体外语句。

2. 举例:通过for循环打印输出一个切片。

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}           //数组字面值初始化
 arr2 := arr1[0:3]                                               //切片截取
 for i := 0; i < len(arr2); i++ {                                    //for循环打印
    fmt.Println(arr2[i])
 }

终端输出: img

结构解析:

 arr1 := [5]string{"知链", "区块链", "人才", "培养", "摇篮"}           //数组字面值初始化

切片字面值初始化:在此语句中通过短类型声明将切片声明并指定出切片类型和切片长度(即切片元素的数据存储的内存空间),然后通过=(赋值运算符)将数据赋值给切片元素的数据存储空间。

arr2 := arr1[0:3]                                               //切片截取

切片截取:在此语句中通过短类型声明将切片声明并指定出切片类型,切片长度和切片容量,切片的截取是基于现有的切片或者数组创建,使用[i:j]这样的操作符即可。它表示以i索引开始,到j索引结束,截取原数组或者切片,创建而成的新切片。新切片的值包含原切片的i索引,但是不包含j索引。

 for i := 0; i < len(arr2); i++ {                                    //for循环语句
    fmt.Println(arr2[i])
 }

for循环语句:在Go中, for循环根据循环计数器或循环变量实现代码的重复执行。函数编译进入for循环语句中时,先执行初始化语句以后开始执行条件判断语句(判断数组的长度与初始化赋值大小比较) 进行判断说明,确定其结果为true还是false,且如果为false时,则循环会结束,如果是true则继续向下执行从而执行循环体语句(循环体打印输出切片对应的索引值和相应的元素数据),循环体语句结束以后执行条件控制语句再重复判断条件的执行,从而实现条件的循环判断输出。