golang切片内存应用技巧详解
作者:kevinyan 发布时间:2024-05-21 10:19:38
在 Go 语言中切片是使用非常频繁的一种聚合类型,它代表变长的序列,底层引用一个数组对象。一个切片由三个部分构成:指针、长度和容量。指针指向该切片自己第一个元素对应的底层数组元素的内存地址。
切片的类型声明如下:
type slice struct {
array unsafe.Pointer
len int
cap int
}
多个切片之间可以共享底层数组的数据,并且引用的数组区间可能重叠。利用切片 的这个特性我们可以在原有内存空间中对切片进行反转、筛选和去重等操作,这样就不用声明一个指向新内存的切片来存储结果,从而节省了内存空间以及扩展底层数组的消耗,这在切片长度足够大时效果就会非常显著。
下面这些例子都是在切片底层数组的内存空间上进行的操作,需要注意的是这些操作在底层数组上生成新切片的同时也会更改底层数组。
删除指定位置的元素
下面的函数从原切片中删除索引位置i上的元素
func remove(slice []int, i int) []int {
copy(slice[i:], slice[i+1:])
return slice[:len(slice)-1]
}
func main() {
s := []int{5, 6, 7, 8, 9}
fmt.Println(remove(s, 2)) // "[5 6 8 9]"
}
内置的copy函数可以方便地将一个切片复制另一个相同类型的切片上。
筛选元素
下面的函数从输入的源切片中筛选出满足条件的切片元素,返回一个满足条件的元素组成的新切片。
type funcType func(T) bool //代表筛选逻辑函数,可以按需实现
func filter(a []T, f funcType) []T {
b := a[:0]
for _, x := range a {
if f(x) {
b = append(b, x)
}
}
return b
}
反转切片
func reverse(a []T) []T {
for i := len(a)/2-1; i >= 0; i-- {
opp := len(a)-1-i
a[i], a[opp] = a[opp], a[i]
}
return a
}
分组切片
下面的函数接收一个[]int 类型的源切片actions, 返回一个按指定长度分组的嵌套切片(解释起来好难,用过PHP 的同学可以理解为 Go 版本的array_chunk 函数,没用过的看下面例子)。假设切面值为:[]int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9},设置分组中元素长度batchSize为3,函数调用后返回的分组后的切片为[[0 1 2] [3 4 5] [6 7 8] [9]]
func chunk(actions []int, batchSize int) []int {
var batches [][]int
for batchSize < len(actions) {
actions, batches = actions[batchSize:], append(batches, actions[0:batchSize:batchSize])
}
batches = append(batches, actions)
return batches
}
func main() {
actions := []int{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
batchSize := 3
chunks = chunk(actions, batchSize)
//chunks 为[[0 1 2] [3 4 5] [6 7 8] [9]]
}
这里顺便说一下,完整的切片表达式形式如下:
input[low:high:max]
最后一个 max 的作用是,生成的切片的cap(容量)为max - low。
原地去重(只针对可比较的切片类型)
import "sort"
func main() {
in := []int{3,2,1,4,3,2,1,4,1} // any item can be sorted
sort.Ints(in)
j := 0
for i := 1; i < len(in); i++ {
if in[j] == in[i] {
continue
}
j++
in[j] = in[i]
}
result := in[:j+1]
fmt.Println(result) // [1 2 3 4]
}
文章中部分例子来自golang 官方的 GitHub 的 wiki ,在这个 wiki 里介绍了很多的切片使用技巧,了解更多可以访问golang 的 GitHub Wiki https://github.com/golang/go/wiki/SliceTricks#filtering-without-allocating
来源:https://juejin.im/post/5de63b35f265da33df77d206


猜你喜欢
- scanner.php <?php /**************PHP Web木马扫描器**********************
- 1.随机翻转(水平和垂直)torchvision.transforms.RandomVerticalFlip函数和torchvision.t
- 这是工作期间同事想要个截完图之后可以显示并且永远前置的截图小工具(即不会被其他程序覆盖)直接上代码:# # -*- coding: utf-
- 查看MySQL执行的语句想实时查看MySQL所执行的sql语句,类似mssql里的事件探查器。对my.ini文件进行设置,打开文件进行修改:
- 以下均在本人虚拟机上进行1.安装pip3sudo apt install python3-pip2.安装虚拟环境sudo apt insta
- 1、可以控制左横向滚动还是右横向滚动。2、鼠标悬停上时暂停滚动,移开后恢复滚动。3、间歇时间按需调整,但不要低于容器向左/右移动的时间。JA
- flash param参数和属性下列标记属性和参数描述了由“发布”命令创建的 HTML 代码。在编写自己的用于显示 Flash 内容的 HT
- 一、前言刚开始学Python的小伙伴可能会觉得每次写Python打开Cmd或者idle有点烦躁,没有代码补全也没有格式提示等。所以直接上手了
- 如何制作一个搜索引擎链接程序?多收集几个网站的,然后我们引用它到自己的页面中。接下来,我们要创建页面用于搜索:<center>&
- 一、前言一个非常强的反爬虫方案 —— 禁用所有 HTTP 1.x 的请求!现在很多爬虫库其实对 HTTP/2.0 支持得不好,比如
- 一、闭包闭包从形式上来说是在外部函数中定义内部函数,并且内部函数引用了外部函数的变量,此变量叫做自由变量。或者说是将组成函数的语句和这些语句
- 一、责任链模式责任链模式,将多个处理方法连接成一条链条,请求将在这条链条上流动直到该链条中有一个节点可以处理该请求。通常这条链条是一个对象包
- PHP htmlspecialchars() 函数实例把预定义的字符 "<" (小于)和 ">&q
- 用Open() 函数打开文件打开文件的常用方法是:open(FH, "< $filename") &nb
- 在按钮旁边加文字1.打开editor/js/ 两个js文件fckeditorcode_gecko.js fckeditorcode_ie.j
- Paramiko 是由 Python 语言编写的一个扩展模块,提供了基于 SSHv2 协议 (包括客户端和服务端)的多种功能实现。通常被用来
- 方法说明:同步版的 fs.realpath() 。语法:fs.realpathSync(path, [cache])由于该方法属于fs模块,
- 在做task中,需要将TXT文本中的某一项注释修改,但是python对txt文本只有写入和读取两种操作。我采用的方法是:1.读取txt文件,
- 我就废话不多说了,直接上代码吧!import Imagefrom datetime import datetimeimport osstr
- 把文件解压到一个目录下这是解压后的目录 将my.ini文件考进去 双击打开my.ini找到这两行更改成自己的解压路径保存