Go语言中的数组和切片 len cap append copy

简介: Go语言中的数组和切片 len cap append copy

aHR0cHM6Ly9jb2RpbmczbWluLm9zcy1hY2NlbGVyYXRlLmFsaXl1bmNzLmNvbS9jb2RpbmczbWluLzIwMjAtMDUtMDUtMTUzODMyLmpwZw.png

先来看看Golang中的数组


其实在循环那一节用到过数组,我快速介绍一下。

  • 数组中是固定长度的连续空间(内存区域)
  • 数组中所有元素的类型是一样的


  var a1 [10]int
  //初始化数组
  var b1 = [5]float32{1000.0, 2.0, 3.4, 7.0, 50.0}

多维数组


//声明二维数组,只要 任意加中括号,可以声明更多维,相应占用空间指数上指
  var arr [3][3]int
  //赋值
  arr = [3][3]int{
    {1, 2, 3},
    {2, 3, 4},
    {3, 4, 5},
  }


何谓切片?


类比c语言,一个int型数组int a[10],a的类型是int*,也就是整型指针,而c语言中可以使用malloc()动态的分配一段内存区域,c++中可以用new()函数。例如:

int* a = (int *)malloc(10);
int* b = new int(4);

此时,ab的类型也是int*ab此时分配内存的方式类似于go语言中的切片。

Go的数组和切片都是从c语言中延续过来的设计。


有何不同?


var sliceTmp []int


可以看到和c不同的是,go可以声明一个空切片(默认值为nil),然后再增加值的过程中动态的改变切片值大小。


怎么动态增加?


增加的方式只有一种,使用append函数追加。

sliceTmp = append(sliceTmp, 4)
sliceTmp = append(sliceTmp, 5)

每个切片有长度len和容量cap两个概念,长度是我们最熟知的,和数组长度相同,可以直接用来遍历。


for _,v := range slice1{
    fmt.Println(v)
  }


用切糕来对比


aHR0cHM6Ly9jb2RpbmczbWluLm9zcy1hY2NlbGVyYXRlLmFsaXl1bmNzLmNvbS9jb2RpbmczbWluLzIwMjAtMDUtMDUtMDgwNjE3LmpwZw.png


每个切片,在声明或扩建时会分配一段连续的空间,称为容量cap,是不可见的;真正在使用的只有一部分连续的空间,称为长度len,是可见的。


每次append时,如果发现cap已经不足以给len使用,就会重新分配原cap两倍的容量,把原切片里已有内容全部迁移过去。


新分配的空间也是连续的,不过不一定直接在原切片内存地址处扩容,也有可能是新的内存地址。


切片的长度与容量,len cap append copy

slice1 := []int{1, 2, 3}


普通切片的声明方式,长度和容量是一致的。

len=3 cap=3 slice=[1 2 3]


当然,控制权在我们手上,我们可以自己控制长度和容量,

slice1 = make([]int, 3, 5) // 3 是长度 5 是容量


输出

len=3 cap=5 slice=[0 0 0]


尝试使用一般的方式扩容

slice1[len(slice1)] = 4 
//报错 panic: runtime error:
//index out of range [3] with length 3


这种方式是会报错的,虽然容量是 5 ,但是数组长度是3,这里是以长度为准,而不是容量,append内部如果超过容量相当于创建了一个新数组,每个新数组都是定长的,只不过外部是切片。

尝试扩容

slice1 = append(slice1, 4)


输出,可以发现len扩容了!

len=4 cap=5 slice=[0 0 0 4]


让我们连续扩容,让容量超过5

slice1 = append(slice1, 5)
slice1 = append(slice1, 6) // 到这里长度超过了容量,容量自动翻倍为 5*2


输出

len=6 cap=10 slice=[0 0 0 4 5 6]


上面的过程,我 用自己的代码模拟一遍

// 上面容量自动翻倍的过程可以看作和下面一致
  slice1 = make([]int, 3, 5) // 3 是长度 5 是容量
  slice1 = append(slice1, 4)
  slice1 = append(slice1, 5)
// 长度不变,容量自动翻倍为 5*2
  slice2 := make([]int, len(slice1), 
          (cap(slice1))*2)
  // 拷贝 slice1 的内容到 slice2 
  // 注意是后面的拷贝给前面
  copy(slice2, slice1) 
  slice2 = append(slice2, 6) 

所以,你理解容量,长度的概念了吗?


aHR0cHM6Ly9jb2RpbmczbWluLm9zcy1hY2NlbGVyYXRlLmFsaXl1bmNzLmNvbS9jb2RpbmczbWluLzIwMjAtMDQtMjgtOTZjZDBlZDNiMzAyNDAzNjk1MzE1ODMxYzYyOWQ3ZTMlMjAtNC0ucG5n.png

相关文章
|
3月前
|
存储 JSON 安全
Go语言切片,使用技巧与避坑指南
Go语言中的切片(Slice)是动态引用数组的高效数据结构,支持扩容与截取。本文从切片基础、常用操作到高级技巧全面解析,涵盖创建方式、`append`扩容机制、共享陷阱及安全复制等内容。通过代码示例详解切片特性,如预分配优化性能、区分`nil`与空切片、处理多维切片等。掌握这些核心知识点,可编写更高效的Go代码。
134 2
|
2月前
|
数据采集 机器学习/深度学习 存储
Go语言实战案例 - 找出切片中的最大值与最小值
本案例通过实现查找整数切片中的最大值与最小值,帮助初学者掌握遍历、比较和错误处理技巧,内容涵盖算法基础、应用场景及完整代码示例,适合初学者提升编程能力。
|
29天前
|
数据采集 Go API
Go语言实战案例:多协程并发下载网页内容
本文是《Go语言100个实战案例 · 网络与并发篇》第6篇,讲解如何使用 Goroutine 和 Channel 实现多协程并发抓取网页内容,提升网络请求效率。通过实战掌握高并发编程技巧,构建爬虫、内容聚合器等工具,涵盖 WaitGroup、超时控制、错误处理等核心知识点。
|
1月前
|
数据采集 JSON Go
Go语言实战案例:实现HTTP客户端请求并解析响应
本文是 Go 网络与并发实战系列的第 2 篇,详细介绍如何使用 Go 构建 HTTP 客户端,涵盖请求发送、响应解析、错误处理、Header 与 Body 提取等流程,并通过实战代码演示如何并发请求多个 URL,适合希望掌握 Go 网络编程基础的开发者。
|
2月前
|
JSON 前端开发 Go
Go语言实战:创建一个简单的 HTTP 服务器
本篇是《Go语言101实战》系列之一,讲解如何使用Go构建基础HTTP服务器。涵盖Go语言并发优势、HTTP服务搭建、路由处理、日志记录及测试方法,助你掌握高性能Web服务开发核心技能。
|
2月前
|
Go
如何在Go语言的HTTP请求中设置使用代理服务器
当使用特定的代理时,在某些情况下可能需要认证信息,认证信息可以在代理URL中提供,格式通常是:
162 0
|
3月前
|
JSON 编解码 API
Go语言网络编程:使用 net/http 构建 RESTful API
本章介绍如何使用 Go 语言的 `net/http` 标准库构建 RESTful API。内容涵盖 RESTful API 的基本概念及规范,包括 GET、POST、PUT 和 DELETE 方法的实现。通过定义用户数据结构和模拟数据库,逐步实现获取用户列表、创建用户、更新用户、删除用户的 HTTP 路由处理函数。同时提供辅助函数用于路径参数解析,并展示如何设置路由器启动服务。最后通过 curl 或 Postman 测试接口功能。章节总结了路由分发、JSON 编解码、方法区分、并发安全管理和路径参数解析等关键点,为更复杂需求推荐第三方框架如 Gin、Echo 和 Chi。
|
3月前
|
Go 索引
Go语言中使用切片需要注意什么?
本文详细讲解了Go语言中切片(Slice)的使用方法与注意事项。切片是对数组连续片段的引用,具有灵活的操作方式。文章从定义与初始化、长度与容量、自动扩容、共享底层数组、复制、边界检查、零值到拼接等方面展开,并配以示例代码演示。通过学习,读者可深入了解切片的工作原理及优化技巧,避免常见陷阱,提升编程效率与代码质量。
95 2
|
4月前
|
分布式计算 Go C++
初探Go语言RPC编程手法
总的来说,Go语言的RPC编程是一种强大的工具,让分布式计算变得简单如同本地计算。如果你还没有试过,不妨挑战一下这个新的编程领域,你可能会发现新的世界。
99 10
|
4月前
|
安全 Go 开发者
Go语言之切片的原理与用法 - 《Go语言实战指南》
切片(slice)是Go语言中用于处理变长数据集合的核心结构,基于数组的轻量级抽象,具有灵活高效的特点。切片本质是一个三元组:指向底层数组的指针、长度(len)和容量(cap)。本文详细介绍了切片的声明与初始化方式、基本操作(如访问、修改、遍历)、长度与容量的区别、自动扩容机制、共享与副本处理、引用类型特性以及常见陷阱。通过理解切片的底层原理,开发者可以更高效地使用这一数据结构,优化代码性能。