Go语言必知必会100问题-20 切片操作实战

news2024/11/18 21:34:37
前言

有很多gopher将切片的length和capacity混淆,没有彻底理清这两者的区别和联系。理清楚切片的长度和容量这两者的关系,有助于我们合理的对切片进行初始化、通过append追加元素以及进行复制等操作。如果没有深入理解它们,缺少高效操作切片的方法,甚至可能导致内存泄露。

切片结构

Go语言中切片的底层是一个数组,也就是说切片中的元素在内存中是连续存储的。如果底层数组元素已满,继续向切片中添加元素,切片会进行扩容操作。在内部实现上,切片包含一个指向底层数组的指针,一个记录数组长度的字段和一个记录数组容量的字段。长度记录的是切片中已添加的元素数量,而容量记录的是数组大小。

切片初始化

下面结合几个具体的程序进行理解。首先来初始化一个给定长度和容量的切片:

s := make([]int, 3, 6)

通过make函数创建切片,它的第一个参数(3)表示切片的长度,是必传参数。第二个参数(6)是非必传参数,该参数表示切片的容量。下图展示了切片s在内存中的分配结果。

在这里插入图片描述

s的底层是一个包含6个元素(容量)的数组,但是因为长度设置为3,所以只初始化了前3个元素。又因为切片中的元素是int类型,所以初始的值为int的类型零值:0. 上图中灰色的格子表示已分配内存但尚未使用。

如果打印切片s的值,得到输出内容是长度范围内的元素值,即[0 0 0]. 如果将s[1]设置为1,则切片中的第二个元素内容会被更新为1,但不会影响切片s的长度和容量。

在这里插入图片描述

访问切片中的元素位置超过切片的长度是不被允许的,将会产生panic, 尽管已经分配的元素个数(切片的容量)比长度大。 例如,下面执行 s[4]=0将会产生pani.

panic: runtime error: index out of range [4] with length 3
append操作

那如何使用剩余灰色的3个空间呢?通过内置的append函数向切片中添加元素。

s = append(s, 2)

可以看到,通过append操作,切片s中添加了一个新的元素2. 元素2存在s中已分配但未使用的空间中(即数组中第4个格子)。如下图所示。此时s的长度变为4.

在这里插入图片描述

如果继续向s添加元素3、4、5, 这个时候元素个数已超过预分配的大小6,此时如何处理呢?

s = append(s, 3, 4, 5)
fmt.Println(s)

执行上面的代码,可以看到输出结果与我们预期的一致,打印 [0 1 0 2 3 4 5].

因为数组是一种大小固定的数据结构,s底层是一个大小为6的数组,所以它只能存储到元素4. 当向里面插入元素5的时候,它已经满了,这时将创建一个新的数组,数组的大小是原来的两倍,然后将原来数组中的元素拷贝到新数组中,最后向新数组中插入元素。处理结果如下图。

在这里插入图片描述

NOTE:在Go语言中,切片在扩容时,新切片的容量大小是旧切片的两倍,直到容量大小为1024,当容量超过1024时,按原来的1.25倍进行扩容。

现在切片s底层关联的是一个新数组,那之前的数组会怎么处理呢?如果它不再被引用,并且是在堆上分配的,则最后将被垃圾回收器(GC)回收。

截取操作

切片截取操作,截取操作的对象是一个数组或切片,从中截取一部分数据,截取的范围是左闭右开区间。下面的代码中,s2是通过截取s1得到的,在内存的结构如下图所示。

s1 := make([]int, 3, 6)
s2 := s1[1:3]

在这里插入图片描述

s1是一个长度为3,容量为6的切片,切片s2是通过s1创建的,两个切片底层引用的是相同的数组。但是,s2下标索引从底层数组的索引1开始,并且容量也与s1不同。如果我们对s1[1]或s2[0]进行更新操作,它们更改的是的底层数组的相同位置值,所以对s1[1]进行更新,将其设置为1,s2[0]的值也同步更新了,此时内存结构如下图所示。

在这里插入图片描述

如果此时执行 s2 = append(s2,2)操作,切片s1会发生变化吗?虽然它们共享的底层数组中的元素已发生变化,第4个格子中的元素被设置为2,但是该索引位置对s1是不可见的,因为它的长度为3, 此时s1和s2在内存中的结构如下。

在这里插入图片描述

现在打印s1和s2的值,输出如下。可以看到,它们的值是不同的,理解这种行为很重要,这样在使用append时就不会做出错误的假设。

s1=[0 1 0], s2=[1 0 2]

NOTE: 切片的底层数组是内部实现,Go开发人员是无法直接操作访问的。唯一的例外是通过对现有数组创建切片。

切片扩容

最后要考虑的一件事是,如果我们不断的将元素append到切片s2中,直到底层数组已满。继续append会产生什么效果?下面通过实验进行说明,继续向s2中append 3个元素.

s2 = append(s2, 3)
s2 = append(s2, 4)
s2 = append(s2, 5)

这样导致会分配一个新的底层数组给s2,因为原来的底层数组已不够容纳元素3、4、5. 此时s1和s2在内存中的结构如下图所示。可以看到,此时s1和s2底层引用的是不同的数组。由于s1是一个长度为3、容量为6的切片,并且它里面装的元素未满,所以继续引用原来的数组。s2新关联新的数组,并且会将s1中与之关联的数据拷贝到新数组中。

在这里插入图片描述

总结

切片长度是切片中已有元素的数量,而切片容量是切片中可以容纳的元素数量。向切片中添加元素,当长度和容量相等时会导致创建具有新容量的新底层数组,复制所有来自前一个数组的元素,并将切片指针更新为新数组。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1505881.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何查看centos7中启动了几个nginx

在 CentOS 7 中,最常用的几种方法如下: 1. 使用 ps 命令 ps 命令可以用来显示当前系统中正在运行的进程。要查看所有 Nginx 进程,可以使用以下命令: ps -ef | grep nginx这个命令会列出所有包含“nginx”字符串的进程。输出中会…

SDM450核心板_高通SDM450安卓核心板模块性能参数

高通SDM450核心板是基于SDM450移动平台开发的一款高性能核心板。采用领先的14纳米技术,该核心板为高端智能设备提供了卓越的性能和优质的体验。板载2GB16GB的内存(可选配4GB32GB),双 ISP(图像传感器处理器)支持丰富的照片细节和双摄像头体验,…

设计模式:观察者模式 ⑧

一、思想 观察者模式是一种常见的设计模式,也称作发布-订阅模式。它主要解决了对象之间的通知依赖关系问题。在这种模式中,一个对象(称作Subject)维护着一个对象列表,这些对象(称作Observers)都…

每日学习笔记:C++ STL 的Array

Array定义 Array模板有两个参数,一个是元素类型,一个是数组大小 Array初始化 Array的操作 Array当作C数组 Array的Tuple接口

NLP:文本相似度计算

前面我们已经实现了把长段的句子,利用HanLP拆分成足够精炼的分词,后面我们要实现“联想”功能,我这里初步只能想到通过文本相似度计算来实现。下面介绍一下文本相似度计算 (当然HanLP也有文本相似度计算的方法,这里我…

Day33-计算机基础3

Day33-计算机基础3 1.根据TCP/IP进行Linux内核参数优化1.1 例1:调整访问服务端的【客户端】的动态端口范围 ,LVS(10-50万并发),NGINX负载,SQUID缓存服务,1.2 企业案例:DOS攻击的案例&#xff1a…

第五十三天| 1143.最长公共子序列、1035.不相交的线、53. 最大子序和

Leetcode 1143.最长公共子序列 题目链接:1143 最长公共子序列 题干:给定两个字符串 text1 和 text2,返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 ,返回 0 。 一个字符串的 子序列 是指这样一个新的字符串&…

no main manifest attribute,in xxx.jar(关于Spring项目,无法在云服务器上运行jar包的解决方法)

目录 问题详情 解决方法 问题详情 项目可以打包正常&#xff0c;但是云服务器上无法运行&#xff0c;报错&#xff1a;no main manifest attribute&#xff0c;in xxx.jar 解决方法 1.查看pom.xml配置文件&#xff0c;检查以下代码&#xff0c;没有则加上&#xff1a; <…

基于springboot+vue实现高校学生党员发展管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现高校学生党员发展管理系统演示 摘要 随着高校学生规模的不断扩大&#xff0c;高校内的党员统计及发展管理工作面临较大的压力&#xff0c;高校信息化建设的不断优化发展也进一步促进了系统平台的应用&#xff0c;借助系统平台可以实现更加高效便捷的党员信息…

P8680 [蓝桥杯 2019 省 B] 特别数的和:做题笔记

目录 思路 代码 题目链接&#xff1a; P8680 [蓝桥杯 2019 省 B] 特别数的和 思路 最开始我思路主要是从数字转字符串上想的。因为我们需要判断每一位是否是特殊数&#xff0c;字符串很容易做到这一点&#xff0c;只是在数字相加这一步不好实现。 需要用到字符串与数字的…

复盘-word

word-大学生网络创业交流会 设置段落&#xff0c;段后行距才有分 word-选中左边几行字进行操作 按住alt键进行选中 word复制excel随excel改变&#xff08;选择性粘贴&#xff09; 页边距为普通页边距定义 ##### word 在内容控件里面填文字&#xff08;调属性&#xff09…

会话_过滤器_监听器笔记

一&#xff1a;会话 1&#xff1a;Cookie&#xff1a; cookie是一种客户端会话技术,cookie由服务端产生,它是服务器存放在浏览器的一小份数据,浏览器以后每次访问该服务器的时候都会将这小份数据携带到服务器去。 服务端创建cookie,将cookie放入响应对象中,Tomcat容器将cookie…

缓解LLM的局限性:微调 VS RAG

原文地址&#xff1a;Knowledge Graphs & LLMs: Fine-Tuning Vs. Retrieval-Augmented Generation 2023 年 6 月 6 日 GitHub&#xff1a;https://github.com/neo4j/NaLLM 大型语言模型 (LLM) 的第一波炒作来自 ChatGPT 和类似的基于网络的聊天机器人&#xff0c;相信在…

Kap - macOS 开源录屏工具

文章目录 关于 Kap 关于 Kap Kap 是一个使用web技术的开源的屏幕录制工具 官网&#xff1a;https://getkap.cogithub : https://github.com/wulkano/Kap 目前只支持 macOS 12 以上&#xff0c;支持 Intel 和 Apple silicon 你可以前往官网&#xff0c;右上方下载 你也可以使…

Spring Boot 中使用 Redis + Aop 进行限流

Spring Boot 中使用 Redis 进行限流&#xff0c;通常你可以采用如下几种方式&#xff1a; 令牌桶算法&#xff08;Token Bucket&#xff09;漏桶算法&#xff08;Leaky Bucket&#xff09;固定窗口计数器&#xff08;Fixed Window Counter&#xff09;滑动日志窗口&#xff08…

自然语言发展历程

一、基础知识 自然语言处理&#xff1a;能够让计算理解人类的语言。 检测计算机是否智能化的方法&#xff1a;图灵测试 自然语言处理相关基础点&#xff1a; 基础点1——词表示问题&#xff1a; 1、词表示&#xff1a;把自然语言中最基本的语言单位——词&#xff0c;将它转…

docker学习(十四)docker搭建私服

docker私服搭建&#xff0c;配置域名访问&#xff0c;设置访问密码 启动registry docker run -d \-p 5000:5000 \-v /opt/data/registry:/var/lib/registry \registrydocker pull hello-world docker tag hello-world 127.0.0.1:5000/hello-world docker push 127.0.0.1:5000…

深入浅出计算机网络 day.1 概论② 因特网概述

当你回头看的时候&#xff0c;你会发现自己走了一段&#xff0c;自己都没想到的路 —— 24.3.9 内容概述 01.网络、互连&#xff08;联&#xff09;网与因特网的区别与联系 02.因特网简介 一、网络、互连&#xff08;联&#xff09;网与因特网的区别与联系 1.若干节点和链路互连…

云原生之容器编排实践-ruoyi-cloud项目部署到K8S:网关服务、认证服务与系统服务

背景 前面搭建好了 Kubernetes 集群与私有镜像仓库&#xff0c;终于要进入服务编排的实践环节了。本系列拿 ruoyi-cloud 项目进行练手&#xff0c;按照 MySQL &#xff0c; Nacos &#xff0c; Redis &#xff0c; Nginx &#xff0c; Gateway &#xff0c; Auth &#xff0c;…

【Linux】深入探究CentOS防火墙(Firewalld):基础概念、常用命令及实例操作

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;Linux ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 Firewalld基础概念&#xff1a; Firewalld常用命令&#xff1a; 启动/停止/重启Firewalld服务&#xff1a; 查看Firewalld状态…