〇、测试前准备

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

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

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

语法:

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

测试一下:

package main

import (
"fmt"
) func main() {
s1 := make([]int, 2) // 等同于:make([]int, 2, 2)
fmt.Printf("slice s1 : %v\n", s1)
fmt.Printf("slice s1-len : %v\n", len(s1))
fmt.Printf("slice s1-cap : %v\n", cap(s1))
s2 := make([]int, 2, 4)
fmt.Printf("slice s2 : %v\n", s2)
s3 := make([]int, 3, 4)
fmt.Printf("slice s3 : %v\n", s3)
fmt.Printf("slice s3-len : %v\n", len(s3))
fmt.Printf("slice s3-cap : %v\n", cap(s3))
}

2.2 append 追加数据 超出 cap

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

package main

import (
"fmt"
) func main() {
data := [...]int{0, 1, 2, 3, 4, 10: 0}
s := data[:2:3]
fmt.Println("data[:2:3]")
fmt.Println(len(s))
fmt.Println(cap(s))
fmt.Println("append(s, 100, 200)")
s = append(s, 100, 200) // 一次 append 两个值,超出 s.cap 限制
fmt.Println(len(s))
fmt.Println(cap(s))
fmt.Println("append(s, 1000, 2000, 3000)")
s = append(s, 1000, 2000, 3000) // 一次 append 两个值,超出 s.cap 限制
fmt.Println(len(s))
fmt.Println(cap(s))
fmt.Println(&s[0], s) // 重新分配底层数组,与原数组无关
fmt.Println(&data[0], data) // 比对底层数组起始指针
}

详解:

  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 位不包含。
package main

import (
"fmt"
) func main() {
data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
ss := data[2:4] // 截取 2~4 位,且不包含 4
fmt.Println(ss)
fmt.Printf("slice len(ss) : %v\n", len(ss))
fmt.Printf("slice cap(ss) : %v\n", cap(ss))
s := data[2:4:7] // 截取 2~4 位,且不包含 4。容量截取到 7 位,且不包含 7
fmt.Println(s)
fmt.Printf("slice len(s) : %v\n", len(s))
fmt.Printf("slice cap(s) : %v\n", cap(s))
s[0] += 100
p := &s[0] // 获取切片 s 中首个数据存储的地址
*p += 10 // *int 获取底层数组元素的指针
s[1] += 200
fmt.Println(s)
fmt.Println(data)
}

2.4 直接修改 struct array/slice 成员

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

package main

import (
"fmt"
) func main() {
d := [5]struct {
x int
}{}
s := d[:]
d[1].x = 10
s[2].x = 20
fmt.Println(d)
fmt.Println(s)
fmt.Printf("%p, %p\n", &d, &d[0])
fmt.Printf("%p, %p\n", &s, &s[0])
}

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

2.5 切片拷贝 copy

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

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

package main

import (
"fmt"
) func main() {
data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println("array data : ", data)
s1 := data[8:]
s2 := data[:5]
fmt.Printf("slice s1 : %v\n", s1)
fmt.Printf("slice s2 : %v\n", s2)
copy(s2, s1) // 短 -> 长
fmt.Printf("copied slice s1 : %v\n", s1)
fmt.Printf("copied slice s2 : %v\n", s2)
fmt.Println("array data : ", data)
fmt.Println("------------------------------------------")
data2 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
fmt.Println("array data2 : ", data2)
s3 := data2[8:]
s4 := data2[:5]
fmt.Printf("slice s3 : %v\n", s3)
fmt.Printf("slice s4 : %v\n", s4)
copy(s3, s4) // 长 -> 短
fmt.Printf("copied slice s3 : %v\n", s3)
fmt.Printf("copied slice s4 : %v\n", s4)
fmt.Println("array data2 : ", data2)
}

2.6 切片遍历

package main

import (
"fmt"
) func main() {
data := [...]int{0, 1, 2}
slice := data[:]
for index, value := range slice {
fmt.Printf("index : %v , value : %v\n", index, value)
}
}

2.7 字符串切片

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

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

Go 语言中字符分两种:

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

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

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

package main

import (
"fmt"
) func main() {
str := "你好,世界!GO!"
fmt.Println(str)
s := []rune(str)
for index, value := range s {
fmt.Printf("index: %v , value : %v\n", index, value)
}
s[3] = '够'
s[4] = '浪'
s = s[:]
str = string(s)
fmt.Println(str)
for index, value := range s {
fmt.Printf("index: %v , value : %v\n", index, value)
}
}

参考: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. SqlSugar子查询

    1.基础教程 1.1 API目录 *****只查一列***** //First: SqlFunc.Subqueryable<School>().Where(s => s.Id ==  ...

  2. Pdfium.Net.Free 一个免费的Pdfium的 .net包装器--快速入门

    Pdfium.Net.Free 支持 .NETFramework 4.0 .NETFramework 4.5 .NETStandard 2.0 可以和PdfiumViewer.Free共同使用预览pd ...

  3. 手把手带你上手swagger3

    配置POM 只需要加一个依赖,并且要注意,swagger3在springboot2.5版本以上会出现问题 <dependency> <groupId>io.springfox& ...

  4. Docker生命周期,一张图秒懂docker

  5. Flink-启动后无法访问WebUI界面(Flink1.16)

    问题描述 通过./bin/start-cluster.sh启动Flink程序,正常启动后无法通过浏览器访问web UI界面,http://192.168.80.133:8081. 问题原因 Flink ...

  6. docker离线安装及设置默认存储目录

    一.离线安装Docker 在内网环境下,一般不能联网在线部署,这时候就需要以离线的方式安装docker.本文介绍在CentOS 7.6环境中离线安装docker的步骤. 1. 下载docker安装包 ...

  7. AI抠图神器RMBG下载介绍

    RMBG是一款先进的AI抠图工具,和其它同类型软件不同的是,RMBG不需要人工勾勒图形轮廓,可以自动识别图像的前景并去除背景,节省大量时间,效果非常惊艳 最新中文版下载: 百度网盘:https://p ...

  8. JS leetcode 寻找数组的中心索引 题解分析

    壹 ❀ 引 今天是的题目来自leetcode的724. 寻找数组的中心索引,做完之后我感觉自己像个憨憨,题目描述如下: 给定一个整数类型的数组 nums,请编写一个能够返回数组"中心索引&q ...

  9. NC24870 [USACO 2009 Dec G]Video Game Troubles

    题目链接 题目 题目描述 Farmer John's cows love their video games! FJ noticed that after playing these games th ...

  10. Reactive 简介

    1. 概念 Reactive 非常适合低延迟.高吞吐量的工作负载. Reactive Processing 是一种范式(规范),它使开发人员能够构建非阻塞的.异步的应用程序,这些应用程序能够处理背压( ...