前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >聊聊 Golang 中的切片和数组

聊聊 Golang 中的切片和数组

作者头像
leoay 技术
发布2023-06-12 14:44:56
1990
发布2023-06-12 14:44:56
举报
文章被收录于专栏:leoay 技术leoay 技术

字数:1467, leoay 技术圈

你好, 我是 leoay, 又好几天不见了,今天我想聊一下 Golang 中切片和数组的区别。

说到数组,我们应该都不陌生吧,因为基本上每种编程语言中有它的身影;而切片呢?也是一种数据结构,python中也有切片的概念。

数组和切片都可以用来存储一组数据。

但是不同的是数组的长度是固定的,而切片则是可变的;切片就类似于一个可变的数组。

其实,在Go语言中数组和切片外表看起来很像,也因此有时候我们很容易搞混淆,下面我就用几个例子对比一下数组和切片的差异。

数组

因为数组是固定长度的,所以在定义数组时,我们必须指定数组的长度

代码语言:javascript
复制
var array1 [3] int   //长度为3的整型数组,默认值是3个0

arr := [5]int{1, 2, 3, 4, 5}   //长度为5的数组,并赋值

var array2 = [...]int{6, 7, 8}  //不声明长度,长度取总元素个数3

array3 := [...] int {1,2,3} //不声明长度的数组,长度取总元素个数3

array4 := [...] int {99:-1}  //长度为100的数组,只有最后一个是-1,其他都是0(大括号中前面一个是最大下标,后面则是对应的值)

和其他语言的数组一样, Golang 的数组也是通过下标访问元素的。

slice

slice,即切片,表示一个拥有相同类型元素的可变长度序列。

slice通常被写为[]T,其中元素的类型都是T;它看上去就像没有长度的数组类型。

数组和slice其实是紧密关联的,它们可以很方便地相互转换。

slice可以看成是一种轻量级的数据结构,可以用来访问数组的部分或者全部元素,而这个数组称之为slice的底层数组。

但是slice和数组是不同的,slice有三个属性:指针,长度和容量,而数组就没有容量这个属性。

其中,指针指向底层数组的第一个可以从slice中访问的元素,这个元素不一定是数组的第一个元素。

长度指的是slice中的元素个数,不能超过slice的容量。

容量的大小通常大于等于长度,会随着元素个数增多而动态变化。Go语言的内置函数len 和 cap 用来返回slice的长度和容量。

下面看一下怎么定义slice:

代码语言:javascript
复制
sllice1 := []int{1, 2, 3}  //注意与数组初始化的区别,在内存中构建一个包括有3个元素的数组,然后将这个数组的应用赋值给s这个Slice

array1 := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 0}  //a是数组
slice2 := array1[2:8]    //从数组中切片构建Slice

slice3 := make([]int, 10, 20)  //make函数初始化,len=10,cap=20

从上面的例子中我们可以看出,数组和slice还是很像,我们可以通过数组构建slice,也可以直接用make创建空的slice,至于make的用法,其实在 Go 中有好几种,后面 涉及到 channel 的文章时再细说。

关于 slice 的扩容

我们已经知道了 slice 的长度不是固定,所以它支持扩容。

在 Go 中我们也用 append 函数来为 slice 扩容。但是这儿有个疑问,如果我们在定义 slice 时已经指定好了长度和容量, 那么扩容时会有什么影响呢?

一般来说,如果我们在对 slice 追加元素时, 容量不够了, 那么其容量一般按照原来的2倍进行扩容, 而长度呢,则会更新为实际的元素个数,可以通过下面这部分代码看效果:

代码语言:javascript
复制
package main 

import "fmt"

func print_info(my_slice []int) {
 fmt.Println("len :",len(my_slice))
 fmt.Println("cap :",cap(my_slice))
 for i,v :=range my_slice{
  fmt.Println("element[",i,"]=",v)
 }
 fmt.Printf("%p", my_slice)
}

func main() {
 slice1 := make([]int,5,6)
 print_info(slice1)
 slice2 := append(slice1,8,9,10)
 print_info(slice02)
}

其实,进一步观察上面的代码,当我们把扩充前后的 slice 的地址打印出来后发现,它们是不一样的,这就说明扩充并不只是简简单单地在原来的 slice 后面追加元素,而是新创建了一个 slice。

实际上新的 slice 中的前面的元素是从原来的slice中拷贝过来的。

好了,今天的这篇文章就写到这里了,怎么样?看完以后是不是觉得对 Go 中数组和 slice 的认识又多了亿点点,如果觉得文章写得 ok,请给个点赞,以后我会花更多时间陪你在技术的海洋中遨游!

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-07-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 leoay技术号 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数组
  • slice
    • 关于 slice 的扩容
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档