〇、测试前准备

本文是在 GO 环境下测试记录系列之一,GO 基本环境部署步骤将略过,直接上代码。

下面是常用命令:【初始化 + 运行 + 编译】

  1. // {GOPATH} 环境变量值, example 项目文件夹名称
  2. {GOPATH}\src\example>
  3. // 运行代码 // xxx.go 为文件全名
  4. go run xxx.go
  5. // 初始化 // 重复初始化提示:go: E:\Project\Go_WorkSpace\src\example\go.mod already exists
  6. go mod init // 初始化成功时没有输出
  7. go mod tidy // 添加缺少的或删除不需要的模块
  8. // 编译,将源代码编译成可执行程序(.exe) // 可选项:-o xxx.exe 自定义应用程序名
  9. go build [-o xxx.exe]

一、Slice 简介

slice 并不是数组或数组指针。它通过内部指针和相关属性引用数组片段,以实现变长方案。它有如下特点:

  • 切片是数组的一个引用,因此切片是引用类型。但自身是结构体,值拷贝传递。
  • 切片的容量(cap)可以改变,因此,切片可以视作是一个可变的数组。
  • 切片遍历方式和数组一样,可以用 len() 求长度。表示可用元素数量,读写操作不能超过该限制。
  • cap 可以求出 slice 最大扩张容量,不能超出数组限制。0 <= len(slice) <= len(array),其中 array 是 slice 引用的数组。注意:
  • 当通过 append 方法往 slice 中添加元素时超过了其容量时,会自动扩充,此时会大于 slice 的容量,就会重新分配底层数组,即便原数组并未填满,且与原 array 无关。
  • 如果 slice == nil,那么 len、cap 结果都等于 0。

切片的定义:var 变量名 []类型,比如:var str []string、var arr []int。

二、测试记录

2.1 make 创建切片

语法:

  1. var slice []type = make([]type, len) // 全局变量
  2. slice := make([]type, len) // 局部变量
  3. slice := make([]type, len, cap)

测试一下:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. s1 := make([]int, 2) // 等同于:make([]int, 2, 2)
  7. fmt.Printf("slice s1 : %v\n", s1)
  8. fmt.Printf("slice s1-len : %v\n", len(s1))
  9. fmt.Printf("slice s1-cap : %v\n", cap(s1))
  10. s2 := make([]int, 2, 4)
  11. fmt.Printf("slice s2 : %v\n", s2)
  12. s3 := make([]int, 3, 4)
  13. fmt.Printf("slice s3 : %v\n", s3)
  14. fmt.Printf("slice s3-len : %v\n", len(s3))
  15. fmt.Printf("slice s3-cap : %v\n", cap(s3))
  16. }

2.2 append 追加数据 超出 cap

测试目的:通过 append 方法添加元素,超出 slice 的 cap 值。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. data := [...]int{0, 1, 2, 3, 4, 10: 0}
  7. s := data[:2:3]
  8. fmt.Println("data[:2:3]")
  9. fmt.Println(len(s))
  10. fmt.Println(cap(s))
  11. fmt.Println("append(s, 100, 200)")
  12. s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制
  13. fmt.Println(len(s))
  14. fmt.Println(cap(s))
  15. fmt.Println("append(s, 1000, 2000, 3000)")
  16. s = append(s, 1000, 2000, 3000) // 一次 append 两个值,超出 s.cap 限制
  17. fmt.Println(len(s))
  18. fmt.Println(cap(s))
  19. fmt.Println(&s[0], s) // 重新分配底层数组,与原数组无关
  20. fmt.Println(&data[0], data) // 比对底层数组起始指针
  21. }

详解:

  1. data[:2:3]--截取数组 data 的 0~2 不包含 2,结果就是 [0,1],len 长度是 2,cap 容量是 3。
  2. append(s, 100, 200)--往切片 s 中添加两个值,此时结果测长度是 4,大于切片的容量 3,则会自动重新分配底层数组,将切片数组容量自动增加到 6(3*2),并将新值加入新的数组。
  3. 通过对比两个数组起始指针,可发现它们是不同的数组了。

注意:切片数组的容量增加,是在原容量的基础上乘与 2,无论原容量是多少。

2.3 切片自定义截取

通过array[start : end : cap_value]开始和结束的整数值来指定截取范围,cap_value 标识容量。

  • 若从 0 开始,则 start 可省。start 位包含。
  • 若取到 array 最后,则 end 可省。end 位不包含。
  • cap_value 指的是切片数组的容量截止位,为空则默认至原数组末尾。cap_value 位不包含。
  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  7. ss := data[2:4] // 截取 2~4 位,且不包含 4
  8. fmt.Println(ss)
  9. fmt.Printf("slice len(ss) : %v\n", len(ss))
  10. fmt.Printf("slice cap(ss) : %v\n", cap(ss))
  11. s := data[2:4:7] // 截取 2~4 位,且不包含 4。容量截取到 7 位,且不包含 7
  12. fmt.Println(s)
  13. fmt.Printf("slice len(s) : %v\n", len(s))
  14. fmt.Printf("slice cap(s) : %v\n", cap(s))
  15. s[0] += 100
  16. p := &s[0] // 获取切片 s 中首个数据存储的地址
  17. *p += 10 // *int 获取底层数组元素的指针
  18. s[1] += 200
  19. fmt.Println(s)
  20. fmt.Println(data)
  21. }

2.4 直接修改 struct array/slice 成员

如下代码,声明数组并定义其切片数组,然后分别对两者的一个数值位赋值:

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. d := [5]struct {
  7. x int
  8. }{}
  9. s := d[:]
  10. d[1].x = 10
  11. s[2].x = 20
  12. fmt.Println(d)
  13. fmt.Println(s)
  14. fmt.Printf("%p, %p\n", &d, &d[0])
  15. fmt.Printf("%p, %p\n", &s, &s[0])
  16. }

由上结果可知,数组和切片的实际值指的是同一个段内存中的数据,切片只是增加了对数组的一个引用。

2.5 切片拷贝 copy

函数 copy 在两个 slice 间复制数据,复制长度以 len 小的为准(换句话说就是,将重叠位的数据进行复制)。两个 slice 可指向同一底层数组,允许元素区间重叠。

应及时将所需数据 copy 到较小的 slice,以便释放超大号底层数组内存。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  7. fmt.Println("array data : ", data)
  8. s1 := data[8:]
  9. s2 := data[:5]
  10. fmt.Printf("slice s1 : %v\n", s1)
  11. fmt.Printf("slice s2 : %v\n", s2)
  12. copy(s2, s1) // 短 -> 长
  13. fmt.Printf("copied slice s1 : %v\n", s1)
  14. fmt.Printf("copied slice s2 : %v\n", s2)
  15. fmt.Println("array data : ", data)
  16. fmt.Println("------------------------------------------")
  17. data2 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
  18. fmt.Println("array data2 : ", data2)
  19. s3 := data2[8:]
  20. s4 := data2[:5]
  21. fmt.Printf("slice s3 : %v\n", s3)
  22. fmt.Printf("slice s4 : %v\n", s4)
  23. copy(s3, s4) // 长 -> 短
  24. fmt.Printf("copied slice s3 : %v\n", s3)
  25. fmt.Printf("copied slice s4 : %v\n", s4)
  26. fmt.Println("array data2 : ", data2)
  27. }

2.6 切片遍历

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. data := [...]int{0, 1, 2}
  7. slice := data[:]
  8. for index, value := range slice {
  9. fmt.Printf("index : %v , value : %v\n", index, value)
  10. }
  11. }

2.7 字符串切片

string 底层就是一个 byte 的数组,因此,也可以进行切片操作。

组成每个字符串的元素叫做“字符”,可以通过遍历或者单个获取字符串元素获得字符。 字符用单引号(’)包裹起来。

Go 语言中字符分两种:

  • byte 型(或 uint8 类型),代表了 ASCII 码的一个字符,用于表示字母、数字、标点等英文状态的符号;
  • rune 类型,代表一个 UTF-8 字符,实际上是一个 int32,用于表示除英文外其他国家语言文字、符号等字符。

因此 rune 类型可以是由一个或多个 byte 类型组成。

如下示例代码,将“世界”修改为“够浪”,其对应的 UTF-8 字符也随之改变。

  1. package main
  2. import (
  3. "fmt"
  4. )
  5. func main() {
  6. str := "你好,世界!GO!"
  7. fmt.Println(str)
  8. s := []rune(str)
  9. for index, value := range s {
  10. fmt.Printf("index: %v , value : %v\n", index, value)
  11. }
  12. s[3] = '够'
  13. s[4] = '浪'
  14. s = s[:]
  15. str = string(s)
  16. fmt.Println(str)
  17. for index, value := range s {
  18. fmt.Printf("index: %v , value : %v\n", index, value)
  19. }
  20. }

参考:http://www.topgoer.com/http://www.topgoer.com/go%E5%9F%BA%E7%A1%80/%E5%88%87%E7%89%87Slice.html

slice 切片数组测试记录【GO 基础】的更多相关文章

  1. golang基础---Slice切片

    切片Slice在go语言中是单独的类型(指向底层的数组),不同于python(对可迭代对象操作的工具),注意区分数组和slice的区别 定义一个空slice,格式var s []int,这种既没有长度 ...

  2. golang 数组以及slice切片

    老虞学GoLang笔记-数组和切片   数组 Arrays 数组是内置(build-in)类型,是一组同类型数据的集合,它是值类型,通过从0开始的下标索引访问元素值.在初始化后长度是固定的,无法修改其 ...

  3. golang:slice切片

    一直对slice切片这个概念理解的不是太透彻,之前学习python的就没搞清楚,不过平时就用python写个工具啥的,也没把这个当回事去花时间解决. 最近使用go开发又遇到这个问题,于是打算彻底把这个 ...

  4. slice 切片实现 Slice object interface

    1.Python切片对象可以为任意类型 https://github.com/python/cpython/blob/master/Include/sliceobject.h /* Slice obj ...

  5. JUnit5学习之六:参数化测试(Parameterized Tests)基础

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

  6. linux .net mono方案测试记录与报告(一)

    第一阶段 linux .net 方案测试 硬件为4核8线程的笔记本i7-4710mq 分配了4个线程 情况下 1.方案一 nginx+fastcgi-mono-server4方式 性能为每秒处理140 ...

  7. golang slice切片的原理以及内置函数cap, len

    golang中slice(切片)是常用的类型, slice是对数组进行封装 package main import ( "fmt" "strconv") fun ...

  8. Go语言核心之美 3.2-slice切片

    Slice(切片)是长度可变的元素序列(与之相应,上一节中的数组是不可变的),每一个元素都有同样的类型.slice类型写作[]T.T是元素类型.slice和数组写法非常像,差别在于slice没有指定长 ...

  9. Go - Slice 切片

    概述 切片是一种动态数组,比数组操作灵活,长度不是固定的,可以进行追加和删除. len() 和 cap() 返回结果可相同和不同. 声明切片 //demo_7.go package main impo ...

  10. HDFS部署测试记录(2019/05)

    目录 HDFS部署测试记录 0.HDFS基础知识 1.基本组成结构与文件访问过程 2.NameNode启动时如何维护元数据 3.HDFS文件上传流程 1.系统环境 1.安装大致记录: 2.磁盘分区 3 ...

随机推荐

  1. 使用svn.externals(外链)提升美术多个svn目录的svn up速度

    svn up多个目录耗时大 svn上的美术资源项目,在打包机上对一个很久没有变化的目录进行svn up也是需要消耗不少时间的,特别打包时需要对多个目录进行svn up,比如空跑54个目录的svn up ...

  2. 深度学习应用篇-推荐系统[11]:推荐系统的组成、场景转化指标(pv点击率,uv点击率,曝光点击率)、用户数据指标等评价指标详解

    深度学习应用篇-推荐系统[11]:推荐系统的组成.场景转化指标(pv点击率,uv点击率,曝光点击率).用户数据指标等评价指标详解 1. 推荐系统介绍 在网络技术不断发展和电子商务规模不断扩大的背景下, ...

  3. 使用 arxiv-sanity &paperwithcode 跟进最新研究领域的文章

    1.arxiv-sanity介绍 arxiv.org是一个非常大的预印本资源库,里面有大量的最新的论文,但缺点是浏览.搜索和排序不是很方便.这个资源库每天会更新大量的论文,如果通过手动搜索和浏览则效率 ...

  4. 【5】OpenCV2.4.9实现图像拼接与融合方法【SURF、SIFT、ORB、FAST、Harris角点 、stitch 】

    相关文章: [1]windows下安装OpenCV(4.3)+VS2017安装+opencv_contrib4.3.0配置 [2]Visual Studio 2017同时配置OpenCV2.4 以及O ...

  5. UDP通信 [补档-2023-07-22]

    UDP通信 6-1 简介 ​ UDP通信是面向无链接的,不稳定,不可靠,不安全的一种通信方式.TCP在通信前发送方会向接收方进行三次握手链接,然后确认双方链接后才会进行数据传输,最后四次挥手保证链接关 ...

  6. 基于客户真实使用场景的云剪辑Timeline问题解答与代码实操

    本文为阿里云智能媒体服务IMS「云端智能剪辑」实践指南第6期,从客户真实实践场景出发,分享一些Timeline小技巧(AI_TTS.主轨道.素材对齐),助力客户降低开发时间与成本. 欧叔|作者 故事的 ...

  7. 案例:推进GTID解决MySQL主主不同步问题

    之前文章介绍过MySQL修改lower_case_table_names参数,如果之前大写存储的表将无法识别,需要特殊处理. 最近遇到一例应用开发人员在修改这个参数之后,为了清除之前大写存储的表,做了 ...

  8. 《ASP.NET Core 微服务实战》-- 读书笔记(第6章)

    第 6 章 事件溯源与 CQRS 在本章,我们来了解一下随着云平台一同出现的设计模式 我们先探讨事件溯源和命令查询职责分离(CQRS)背后的动机与哲学 事件溯源简介 事实由事件溯源而来 我们大脑就是一 ...

  9. CF1859

    A 让 \(c\) 保存数组中所有最大的数,如果所有数都相等则 \(-1\). B 只需要记录每个序列的最小值和次小值,然后对次小值求前后缀和. C 枚举最大值 \(mx\),然后遍历 \(i:n\s ...

  10. Swoole从入门到入土(1)——入坑

    入坑一个话题,总得有入坑的理由.有好多话题可供选择,但是思来想去,对于PHPer进阶与其急着去掌握一门新的语言,匆忙地踏足一个新的知识体系,还不如先把php圈子的技能点攒齐了. 话说Swoole诞生之 ...