slice 切片数组测试记录【GO 基础】

slice,切片,数组,测试,记录,go,基础 · 浏览次数 : 20

小编点评

**2.3 切片自定义截取** ```go data2 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s1 := data2[8:] s2 := data2[:5] copy(s2, s1) ``` **2.5 切片遍历** ```go data := [...]int{0, 1, 2} slice := data[:] for index, value := range slice { fmt.Printf("index : %v , value : %v\\", index, value) } ``` **2.6 切片遍历** ```go str := \"你好,世界!GO!\"\ s := []rune(str) for index, value := range s { fmt.Printf("index: %v , value : %v\\", index, value) } ``` **2.7 字符串切片** ```go str := \"你好,世界!GO!\"\ s := []rune(str) for index, value := range s { fmt.Printf("index: %v , value : %v\\", index, value) } ``` **2.8 切片生成** ```go data := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9} s := make([]string, len(data)) for index, value := range data { s[index] = string(value) } fmt.Println(s) ``` **结果** ``` world 够浪 你好,世界!GO! index: 0 , value : 0 index: 1 , value : 1 index: 2 , value : 2 index: 3 , value : 3 index: 4 , value : 4 index: 5 , value : 5 index: 6 , value : 6 index: 7 , value : 7 index: 8 , value : 8 index: 9 , value : 9 ```

正文

〇、测试前准备

本文是在 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 基础】相似的内容:

slice 切片数组测试记录【GO 基础】

本文记录了在 GO 环境中测试 Slice 的相关示例,有助于记忆和备查。

4.go语言复合类型简述

[TOC] # 1. 本章前瞻 很好,经过很长的时间,你终于来到go语言的复合类型中,这里会介绍go语言的3种复合结构:切片(slice,可变数组),映射(map)和字符串(string)。 有些老手可能会问: 1.那结构体(struct)呢,你怎么不介绍? 答:现在还没法完整地介绍结构体(stru

有关 python 切片的趣事

哈喽大家好,我是咸鱼 今天来讲一个我在实现 python 列表切片时遇到的趣事 在正式开始之前,我们先来了解一下**切片(slice)** 切片操作是访问序列(列表、字符串......)中元素的另一种方法,它可以访问一定范围内的元素,通过切片操作,可以生成一个新的序列 语法如下 ```python

slices in Go 1.21

Go 1.21中新增的 slices包中提供了很多与切片相关的函数,适用于任意类型的切片。 本文内容来自官方文档 BinarySearch 函数签名如下: func BinarySearch[S ~[]E, E cmp.Ordered](x S, target E) (int, bool) Bina

解析类型参数

原文在这里。 由 Ian Lance Taylor 发布于2023年9月26日 slices 包函数签名 slices.Clone 函数很简单:它返回一个任意类型切片的副本: func Clone[S ~[]E, E any](s S) S { return append(s[:0:0], s...

go slice使用

1. 简介 在go中,slice是一种动态数组类型,其底层实现中使用了数组。slice有以下特点: *slice本身并不是数组,它只是一个引用类型,包含了一个指向底层数组的指针,以及长度和容量。 *slice的长度可以动态扩展或缩减,通过append和copy操作可以增加或删除slice中的元素。

[转帖]VMware NVMe支持:vSphere 7.0 U3及未来展望

https://aijishu.com/a/1060000000256123 本文内容参考自《SNIA SDC 2021会议资料& 分享的心路历程》中的一个Slide,《NVMe/TCP in the Enterprise:Next-Gen End-to-End Paradigm for Stora

[转帖]fio 命令入门到跑路

fio是一种I / O工具,用于基准测试和压力/硬件验证。它支持19种不同类型的I / O引擎(sync,mmap,libaio,posixaio,SG v3,splice,null,network,syslet,guasi,solarisaio等),I / O优先级(适用于较新的Linux内核)

[转帖]【详细齐全】FIO使用方法 及参数解析(文章末尾)

linux 使用FIO测试磁盘iops 方法详解 FIO是测试IOPS的非常好的工具,用来对硬件进行压力测试和验证,支持13种不同的I/O引擎, 包括:sync,mmap, libaio, posixaio, SG v3, splice, null, network, syslet, guasi,

[转帖]文件系统读写性能fio测试方法及参数详解

简介 Fio 是一个 I/O 工具,用来对硬件进行压力测试和验证,磁盘IO是检查磁盘性能的重要指标,可以按照负载情况分成照顺序读写,随机读写两大类。 Fio支持13种不同的I/O引擎,包括:sync, mmap, libaio, posixaio, SG v3, splice, null, netw