[go学习笔记.第七章.数组和切片] 4.切片的三种使用方式以及注意事项和使用细节

一.切片的使用

方式一

        定义一个切片,然后让切片去引用一个已经创建好的数组,案例如下:

package main

import (
	"fmt"
)

func main() {
	//演示切片的基本使用
	var intArr  [5]int = [...]int{1,2,3,4,5}
	//声明/定义
	//slice := intArr[1:3]
	//1.slice 就是切片名
	//2.intArr[1:3] 表示slice引用到intArr这个数组
	//3.引用intArr这个数组的起始下标为1,最后的下标为3(但不包含3)
	slice := intArr[1:3]
	fmt.Println("intArr = ", intArr)	//[1 2 3 4 5]
	fmt.Println("slice 的元素是 = ", intArr)	//[2 3]
	fmt.Println("slice 的元素个数是= ", len(slice))	// 2
	fmt.Println("slice 的容量 = ", cap(slice))	// 切片的容量是可以动态变化的
}

方式二

        通过make来创建切片

        语法如下:

                var 切片名 []type = make([]type, len, [cap])

         参数说明:

                type 就是数据类型, len 切片大小, cap 指定切片容量,cap是可选的,如果分配了cap,则要求 cap >= len

 案例如下:

package main

import (
	"fmt"
)

func main(){
	//演示切片的使用 make
	var slice []float64 = make([]float64, 5, 10)
	fmt.Println(slice)	// [0 0 0 0 0]
	slice[1] = 11
	slice[3] = 33
	//对于切片,必须make使用
	fmt.Println(slice)	// [0 11 0 33 0]
	fmt.Printf("slice 的size = %d", len(slice))	// 5
	fmt.Printf("slice 的容量 = %d", cap(slice))	//10
}

对上述代码画图分析:

小节: 

        (1).通过make方式创建的切片可以指定切片的大小和容量

        (2).如果没有给切片的各个元素赋值,那么就会使用默认值(int,float => 0, string => "", bool => false)

        (3).通过make方式创建的切片对应的数组是由make底层维护的,对外不可见,即只能通过slice去访问各个元素

方式三

        定义一个切片,直接就指定具体数组,使用原理类似make的方式 

    //方式3
	//定义一个切片,直接指定具体数组,使用原理类似make的方式
	var slice1 []int = []int{11,22,33}
	fmt.Println(slice1)	// [11 22 33]
	fmt.Printf("slice1 的size = %d", len(slice1))	// 3
	fmt.Printf("slice1 的容量 = %d", cap(slice1))	// ? 可变: 这里应该是3

 方式一和方式二的区别

方式一是直接引用数组,这个数组是事先存在的,程序员可见的.

方式二是通过make来创建切片,make也会创建一个切片,是由切片底层维护的,程序员不可见

二.切片的遍历 

方式一

        for循环常规方式遍历

方式二

        for-range结构遍历

	//使用for循环遍历
	var arr [5]int = [...]int{1,2,3,4,5}
	// slice := arr[1:4]	//	[2 3 4]
	slice := arr[:]	//取全部数据: [1 2 3 4 5]
	// slice := arr[:4]	//取[0,4): [1 2 3 4]
	// slice := arr[2:]	//取[2,4]: [3 4 5]
	for i := 0 ;i< len(slice);i++{
		fmt.Printf("slice[%d] = %v ", i, slice[i])	//	slice[0] = 2 slice[1] = 3 slice[2] = 4 
	}

	//使用for-range遍历
	for index, value := range slice {
		fmt.Printf("slice[%d] = %v \n", index, value)	//	slice[0] = 2 slice[1] = 3 slice[2] = 4 
	}

 三.注意事项和使用细节

切片初始化时, var slice = arr[startIndex:endIndex]

说明:

        从arr数组下标为startIndex,取到下标为endIndex的元素(不含arr[endIndex)

        切片初始化时,仍热不能越界,范围在[0~len(arr)]之间,但是可以动态增长

1.var slice = arr[0:end] 可以简写成 var slice = arr[:end]

2.var slice = arr[start:len(arr)] 可以简写成 var slice = arr[start:]

   var slice = arr[0:len(arr)] 可以简写成 var slice = arr[:] 

3.cap是一个内置函数,用于统计切片的容量,即最大可以存放多少个元素

4.切片定义完后,还不能使用,因为本身是一个空的,需要让其引用到一个数组,或者make一个空间切片来使用

5.切片可以继续切片

    //使用for循环遍历
	var arr [5]int = [...]int{1,2,3,4,5}
	// slice := arr[1:4]	//	[2 3 4]
	slice := arr[:]	//取全部数据: [1 2 3 4 5]
	// slice := arr[:4]	//取[0,4): [1 2 3 4]
	// slice := arr[2:]	//取[2,4]: [3 4 5]
	for i := 0 ;i< len(slice);i++{
		fmt.Printf("slice[%d] = %v ", i, slice[i])	//	slice[0] = 2 slice[1] = 3 slice[2] = 4 
	}

	//使用for-range遍历
	for index, value := range slice {
		fmt.Printf("slice[%d] = %v \n", index, value)	//	slice[0] = 2 slice[1] = 3 slice[2] = 4 
	}

	// slice2 := slice[2:3]	// [3]
	slice2 := slice[2:4]	// [3 4]
	fmt.Printf("slice2=%v\n", slice2)	// [3 4]
	slice2[0] = 100	//因为slice,slice2指向的数据空间是同一个,因此slice2[0]=100变化了,其他的也会发生变化
	fmt.Printf("slice2=%v\n", slice2)	// [100 4]
	fmt.Printf("slice=%v\n", slice)	// [1 2 100 4 5]
	fmt.Printf("arr=%v\n", arr)	// [1 2 100 4 5]

 6.用append内置函数,可以对切片进行动态追加

    //用append内置函数,可以对切片进行动态追加
	var slice3 []int = []int{11,22,33,44}
	//注意: append动态追加后,返回一个新的切片,原来的切片不会发生变化, 除非把append后的切片赋给原来的切片
	// slice4 := append(slice3, 55, 66, 77)	
	slice3 = append(slice3, 55, 66, 77)	
	fmt.Printf("slice3=%v\n", slice3)	//11,22,33,44, 55, 66, 77
	// fmt.Printf("slice4=%v\n", slice4)	//11,22,33,44, 55, 66, 77

	//通过append将切片slice3(可以是其他切片)加给slice3
	// slice3 = append(slice3, slice3...)	
	slice3 = append(slice3, slice...)
	fmt.Printf("slice3=%v\n", slice3)

切片append操作底层原理分析 

        (1).切片append操作本质是对数组扩容

        (2).go底层会创建一个新的位数组,newArr (安装扩容后大小)

        (3).将slice原来包含的元素拷贝到新的数组newArr

        (4).slice重新引用到newArr

        (5).注意:newArr是在底层维护的,程序员不可见

7.切片的拷贝操作

    //切片的拷贝操作
	//使用copy内置函数完成切片的拷贝
	var slice4 []int = []int{1,2,3,4}
	var slice5 = make([]int, 10)
	copy(slice5, slice4)	//拷贝slice4到slice5	
	fmt.Printf("slice4= %v\n", slice4)	// 1,2,3,4
	fmt.Printf("slice5= %v\n", slice5)	//1,2,3,4,0,0,0,0,0,0

对上面代码的说明:

        copy(para1,para2)参数的类型就是切片

        按照上面代码来看,slice4,slice5的数据空间是独立,互不影响的,slice4切片中的数据改变不会影响到slice5中的数据 

 8.思考: 下面代码有没有错误

var a[]int = []int{1, 2, 3, 4}    //定义一个切片
var slice = make([]int, 1)    //定义一个切片,默认为[0]
fmt.Println(slice)    // [0]
copy(slice, a)
fmt.Println(slice) // [1]

说明:

        上面代码没有问题,可以运行,最后输出[1]

 原因:

        copy完成切片的拷贝,不过slice的len为1,故只会拷贝a切片中的第一个元素到slice

9.数组和切片的相互转换

//数组转换为切片:  
//1.使用切片操作符[:],它可以返回从指定索引到数组末尾的所有元素,例如:
// 定义一个数组
arr := [5]int{1, 2, 3, 4, 5}
// 将数组转换为切片
slice := arr[:]

//2.使用copy函数
array := [5]int{1, 2, 3, 4, 5}
slice := make([]int, len(array))
copy(slice, array[:])
fmt.Println(slice) // 输出:[1 2 3 4 5]

//切片转换为数组:Go语言中,由于切片是动态数组,不能直接转换为数组,但可以通过copy函数将切片的内容复制到一个新的数组中
slice := []int{1, 2, 3, 4, 5}
var array [5]int
copy(array[:], slice)
fmt.Println(array) // 输出:[1 2 3 4 5]
fmt.Print(reflect.TypeOf(array).Kind()) // array: 通过类型断言判断是一个数组

[上一节][go学习笔记.第七章.数组和切片] 3.切片的基本介绍和入门,切片在内存中的布局分析

[下一节][go学习笔记.第七章.数组和切片] 5.slice和string 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值