当前位置: 首页 > news >正文

go中的切片

数组和切片

一、数组(Array)

  1. 定义与初始化

数组是固定长度的同类型元素的集合,长度在定义时确定,不能改变。

// 定义一个长度为 3 的 int 数组
var arr [3]int// 使用字面量初始化数组
arr := [3]int{1, 2, 3}// 根据初始化的元素个数推导长度
arr := [...]int{1, 2, 3} // 长度为 3
  1. 数组的特点

固定长度:数组的长度在编译时确定,不能动态变化。

值类型:数组是值类型,赋值或传递给函数时会复制整个数组。

内存连续:数组的元素在内存中是连续存储的。

  1. 数组的使用
arr := [3]int{1, 2, 3}
fmt.Println(arr[0]) // 输出 1
arr[1] = 10
fmt.Println(arr)    // 输出 [1 10 3]

切片是对数组的引用,数组的底层是切片的基础。切片可以通过数组创建,但数组不能从切片创建。

二、切片(Slice)

  1. 定义与初始化

切片是对数组的动态视图,长度和容量可以变化。

// 定义一个空切片
var s []int// 使用 make 函数创建切片
s := make([]int, 5)       // 长度为 5,容量为 5
s := make([]int, 5, 10)   // 长度为 5,容量为 10// 使用字面量初始化切片
s := []int{1, 2, 3}
  1. 切片的特点

动态大小:切片的长度和容量可以在运行时动态变化。

引用类型:切片是引用类型,赋值或传递给函数时仅复制指针,不会复制底层数组。

共享底层数组:多个切片可以共享同一个底层数组。

  1. 切片的操作

切片操作:通过切片操作可以创建新的切片。

arr := [5]int{1, 2, 3, 4, 5}
s := arr[1:4] // s 是 [2, 3, 4]

追加元素:使用 append 函数向切片追加元素。

s := []int{1, 2}
s = append(s, 3, 4) // s 变为 [1, 2, 3, 4]

复制切片:使用 copy 函数将一个切片的元素复制到另一个切片。

src := []int{1, 2, 3}
dst := make([]int, len(src))
copy(dst, src) // dst 变为 [1, 2, 3]

删除元素:通过切片操作删除元素。

s := []int{1, 2, 3, 4}
s = append(s[:1], s[2:]...) // 删除索引为 1 的元素,s 变为 [1, 3, 4]
  1. 切片的零值与 nil 切片
var s []int
fmt.Println(s == nil) // 输出 true
fmt.Println(len(s))   // 输出 0
fmt.Println(cap(s))   // 输出 0
  1. 切片的底层结构
    切片的底层是一个结构体,包含以下字段:
type slice struct {array unsafe.Pointerlen    intcap    int
}
array:指向底层数组的指针。len:切片的长度。cap:切片的容量。
  1. 切片的扩容机制

当切片的长度超过其容量时,Go 会自动扩容,通常是将容量翻倍。
扩容时,Go 会分配一个新的底层数组,并将原数组的数据复制到新数组中。
扩容的机制在容量1024以下是两倍扩容。

s := make([]int, 5, 5)
s = append(s, 6) // 扩容,容量增加到 10
  1. 切片是引用类型,但赋值是浅拷贝

    切片是引用类型,但赋值操作仅复制切片的结构体,而不复制底层数组。这意味着多个切片可能共享同一个底层数组。

a := []int{1, 2, 3}
b := a
b[0] = 10
fmt.Println(a) // 输出: [10, 2, 3]

如果需要创建切片的独立副本,应使用 copy 函数:

c := make([]int, len(a))
copy(c, a)
  1. append 的行为可能导致切片共享底层数组

append 函数可能会扩容底层数组,也可能不会。如果扩容,append 会返回一个新的切片;否则,原切片和新切片共享底层数组。

a := []int{1, 2, 3}
b := a
a = append(a, 4) //为了避免共享底层数组,可以在 append 后重新赋值
fmt.Println(a) // 输出: [1, 2, 3, 4]
fmt.Println(b) // 输出: [1, 2, 3]
  1. 切片的零值与空切片的区别

切片的零值是 nil,表示没有底层数组;而空切片是长度为 0 的切片,底层数组的容量可能大于 0。

var s1 []int
s2 := []int{}
fmt.Println(s1 == nil) // 输出: true
fmt.Println(s2 == nil) // 输出: false

在判断切片是否为空时,建议使用 len(s) == 0,而不是 s == nil。

  1. 切片的切片操作不会复制底层数组

对切片进行切片操作(即创建子切片)不会复制底层数组,多个切片可能共享同一底层数组。这可能导致意外的修改。

a := []int{1, 2, 3, 4}
b := a[1:3]
b[0] = 10
fmt.Println(a) // 输出: [1, 10, 3, 4]

如果需要独立的切片副本,应使用 copy 函数:

c := make([]int, len(b))
copy(c, b)

切片的长度是基于切片范围的,而不是数组的元素数量

这里 arr[1:2] 表示从 arr[1] 开始,取到 arr[2](但不包括 arr[2]),所以实际上它只包含一个元素:arr[1]。

brr 是从 arr 中取出的切片,起始位置是 arr[1],结束位置是 arr[2](不包括 arr[2])。因此,brr 只包含一个元素,即 arr[1],其值为 0var arr [3]intfmt.Println(arr) //[0 0 0]brr := arr[1:2]//brr 的内容是 [0],并且它指向 arr[1]。brr = append(brr, 9)//执行 append(brr, 9) 时,Go 会检查 brr 是否有足够的容量来容纳新元素。//brr 的容量是 2,它可以容纳新元素 9。由于 brr 的容量足够,它就会在原来的底层数组上添加 9。fmt.Println(brr) //[0 9]fmt.Println(arr) //[0 0 9]var arr [3]intfmt.Println(arr) //[0 0 0]brr := arr[1:2]brr = append(brr, 9)brr = append(brr, 9)  //第二次append由于容量不足触发了重分配,不再使用arr相同内存fmt.Println(brr) //[0 9 9] fmt.Println(arr) //[0 0 9]
  1. append 在循环中使用可能导致性能问题

    在循环中频繁使用 append 可能导致多次内存分配,影响性能。建议预先分配足够容量的切片。

	s := make([]int, 0, 1000)for i := 0; i < 1000; i++ {s = append(s, i)}
http://www.dtcms.com/a/436188.html

相关文章:

  • 个人网站模板html代码免费百度旧版本下载
  • 网站构建的过程ftp修改wordpress密码
  • 胡恩全10.2作业
  • 增城高端网站建设wordpress 国内不使用方法
  • 百度推广帮做网站长春网站推广优化
  • 【密码学实战】openHiTLS dgst命令行:消息摘要与数字签名
  • 淘宝 网站建设教程视频wordpress栏目id顺序
  • 目前热门的网站建设语言企业网站建设网站优化推广
  • 厦门建网站熊掌号结合网站做seo
  • wordpress站点地图优化网站开发内容怎么写
  • 免费商城版网站广州seo网络推广员
  • php做网站如何架构怎么提高网站访问速度
  • 校园网站建设的参考文献重庆住房和城乡建设厅网站首页
  • Linux应用 文件I/O
  • 网站建设费的摊销乐陵市seo关键词优化
  • 作业部落 WordPress优化wordpress速度
  • 做网站报价北京鑫旺路桥建设有限公司网站
  • 企业cms网站建设考试题如何建设个人网站
  • 大港油田建设官方网站不会PS怎么建网站
  • 公司做网站域名的好处微信公众号关联网站
  • 学校网站建设 分工湖南省住房与城乡建设厅网站
  • 新网站关键词怎么优化合肥网站排名优化公司
  • Spring Boot 消息队列技术整合
  • 34个行政区划总篇
  • 树的重心与直径 性质
  • 请问做卖东西网站怎么建设网站如何弄好几张网站背景
  • 企业网站建设基本要素做折页的网站
  • SysTick 简单总结
  • 地方网站如何做怎么做网页背景
  • 做网站优化竞价区别wordpress主题安装不成功