Go语言必知必会100问题-22 空切片与nil切片有区别吗?

空切片与nil切片有区别吗?

很多开发人员经常混淆nil切片和空切片,不清楚什么时候使用空切片什么时候使用nil,而有些库函数又对这两者使用进行了区分。下面先来看看它们的定义。

  • 空切片是length为0的切片
  • 当切片等于nil时为nil切片

下面是几种不同空切片和nil切片的初始化方法,对于每种情况,都会打印它们的输出。你知道下面程序的输出结果是什么吗?

func main() {var s []stringlog(1, s)s = []string(nil)log(2, s)s = []string{}log(3, s)s = make([]string, 0)log(4, s)
}func log(i int, s []string) {fmt.Printf("%d: empty=%t\tnil=%t\n", i, len(s) == 0, s == nil)
}

上面程序的运行结果如下:

1: empty=true   nil=true
2: empty=true   nil=true
3: empty=true   nil=false
4: empty=true   nil=false

通过输出可以看到,上面四种切片empty都为true,即它们都是空切片,它们的length都为0. 因此nil切片都是空切片。但是只有前两种情况是nil切片。在具体环境中,使用哪种方法更好呢?有两点需要注意:

  • 两者在内存分配方面有很大的不同,初始化一个nil切片不会实际分配内存,相反,初始化一个空切片会分配内存
  • 无论是nil切片还是空切片,都可以调用内置的append函数,例如。
var s1 []string
fmt.Println(append(s1, "foo")) // [foo]

因此,如果一个函数返回一个切片,我们不应该像在其它编程语言中那样,出于防御原因返回一个空切片。因为nil切片不需要任何分配,所以我们应该倾向于返回nil切片而不是空切片。下面这个函数返回一个字符串:

func f() []string {var s []stringif foo() {s = append(s, "foo")}if bar() {s = append(s, "bar")}return s
}

如果foo和bar都为false,不会向s中添加任何内容。为了防止多余的分配内存操作,最佳的方法采用上面的方法1(var s []string). 虽然也可以采用第4种方法( make([]string,0)), 但是与方法1相比,不会带来任何收益,因为它会分配内存。但是,在我们已知要申请切片的长度情况下,应该使用方法4. s:=make([]string,length), 像下面的程序一开始就初始化切片长度,这样可以避免额外的内存分配和复制。

func intsToStrings(ints []int) []string {s := make([]string, len(ints))for i, v := range ints {s[i] = strconv.Itoa(v)}return s
}

剩余未讨论的方法2 s:=[]string(nil)和方法3 s:=[]string{}中,方法2使用的最不广泛,只是可以用作语法糖,因为我们可以在一行代码中完成定义一个nil切片并完成元素添加操作,示例程序如下。如果采用方法1(var s []string), 则需要两行代码, 虽然这种优化对可读性没有实质性帮助,但仍值得了解。

s := append([]int(nil), 42)

NOTE:在本系列的第24篇文章中,可以看到使用nil切片的另一个理由。

现在来看方法3,s:=[]string{}, 它比较适用在创建具有初始元素切片的场景。

s := []string{"foo", "bar", "baz"}

如果我们创建的切片没有初始化元素,则没有必要使用上述方法。一些golang linter会捕获到方法3在没有初始化元素的时候,推荐使用方法1,我们应该知道这种修改实质是将空切片调整为nil切片。

我们也要留意,有些库对空切片和nil切片在处理时有区别。例如json库 encoding/json. 下面的例子中都是对struct进行序列化,结构体1中赋值的是nil切片,结构体2中赋值的是空切片。

var s1 []float32customer1 := customer{ID:         "foo",Operations: s1,
}
b, _ := json.Marshal(customer1)
fmt.Println(string(b))s2 := make([]float32, 0)customer2 := customer{ID:         "bar",Operations: s2,
}
b, _ = json.Marshal(customer2)
fmt.Println(string(b))

运行上述程序得到如下结果,可以看到它们的结果是不同的。nil切片序列化后的值为null, 空切片序列化后的值为[]. 如果解析JSON的客户端对null和[]有严格的区分,需要特别留意这一点,否则会产生bug.

{"ID":"foo","Operations":null}
{"ID":"bar","Operations":[]}

encoding/json 并不是唯一一个区分 nil 切片和空切片的标准库,标准库 reflect 中 DeepEqual函数在比较nil切片和空切片时会返回false, 这一点在单元测试的时候要特别小心。

不管什么场合,无论是标准库还是第三方库,我们都要留意nil切片和空切片存在区别,如果使用不当,可能会引发问题。

总结,在Go语言中,nil切片和空切片是有区别的。nil切片与nil相等,空切片的长度为0,但是它不等于nil。重要的一点是 nil切片不会分配内存,空切片会分配内存。具体使用哪种方法更好需要具体问题具体分析。如果能够确定最后返回的切片为空,则推荐使用 var s []string, 如果在初始化时已知道切片的长度,则采用make([]string,length)最好,[]string(nil)提供了一种语法糖,方便添加元素操作。最后一点,如果在进行初始化时没有元素,则避免使用 []string{}, 还要留意标准库和第三方库对nil切片和空切片处理可能存在不同,如果使用不当会产生意料之外的结果。

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

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

相关文章

salesforce || System.FinalException: Record is read-only Trigger.

以下是错误代码示范 会报错:System.FinalException: Record is read-only Trigger. trigger MoneyTrigger on Money__c (after insert, after update) {Date startDay = Date.newInstance(2023,12,26);if(Trigger.isAfter && Trigger.isInsert){for (Money__c moneys…

一起玩儿3D打印机——01 3D打印机初探

摘要:本文介绍3D打印技术的基本知识以及3D打印机的结构分类和组成 3D打印技术这几年得到了快速的发展,在一些特定领域和特定行业逐渐被越来越多的人所接受并大量使用。与之相关的供应链和产业链也日益壮大,并形成了完善的体系。 这次之所以…

EF框架常见异常处理汇总

EF框架使用常见异常处理 同一个实体被多次tracked的问题Json字符串转换的对象赋值时 同一个实体被多次tracked的问题 错误提示 The instance of entity type ‘XXXX’ cannot be tracked because another instance with the same key value for {‘Key’} is already being tr…

蓝桥杯刷题7

目录 1. 字母数 2. 列名 3. 大乘积 4. 最大连通 5. 星期几 1. 字母数 public class Main {public static void main(String[] args) {int num 2023;while(true) {String mInteger.toString(num,16);if(m.matches("^[a-f]$")){System.out.println(num);break;}n…

Linux环境安装配置JDK11

文章目录 第一步:上传JDK11安装包第二步:解压安装包第三步:修改环境变量第四步、测试是否安装成功总结 JDK 11 是 Java 开发工具包(Java Development Kit)的一个版本,它是由 Oracle 公司开发和发布的。以下…

集成Mybatis Generator dao层代码生成

Mybatis Generator dao层代码生成 介绍 我们在使用mybatis开发的时候,需要去写表的基本的crud,这些咱们通常定义到dao层里面去,而mybatis generator可以帮我们把这件事情自动完成,大大节省时间并且可以规范dao层的代码。 sprin…

关于并发编程的一些总结

并发编程 1.synchronized是什么? synchronized是Java中的一个关键字,主要是为了解决多个线程访问共享资源的同步性,可以保证被它修饰的代码块或方法在任何时间至多只有一个线程执行。 2.synchronized的进化史? 在早期Java版本中&#xf…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的火焰检测系统(Python+PySide6界面+训练代码)

摘要:本研究详述了一种采用深度学习技术的火焰检测系统,该系统集成了最新的YOLOv8算法,并与YOLOv7、YOLOv6、YOLOv5等早期算法进行了性能评估对比。该系统能够在各种媒介——包括图像、视频文件、实时视频流及批量文件中——准确地识别火焰目…

数据分析-Pandas如何观测数据的中心趋势度

数据分析-Pandas如何观测数据的中心趋势度 数据分析和处理中,难免会遇到各种数据,那么数据呈现怎样的规律呢?不管金融数据,风控数据,营销数据等等,莫不如此。如何通过图示展示数据的规律? 数据…

一篇论文回顾 Sora 文生视频技术的背景、技术和应用。

一篇论文回顾 Sora 文生视频技术的背景、技术和应用。 追赶 Sora,成为了很多科技公司当下阶段的新目标。研究者们好奇的是:Sora 是如何被 OpenAI 发掘出来的?未来又有哪些演进和应用方向? Sora 的技术报告披露了一些技术细节&…

趣学前端 | JavaScript标准库

背景 最近睡前习惯翻会书,重温了《JavaScript权威指南》这本书。这本书,文字小,内容多。两年了,我才翻到第十章。因为书太厚,平时都充当电脑支架。 JavaScript标准库 今天阅读的章节是JavaScript标准库,…

数据库规范化设计案例解析

1.介绍 数据库规范化设计是数据库设计的一种重要方法,旨在减少数据库中的冗余数据,提高数据的一致性,确保数据依赖合理,从而提高数据库的结构清晰度和维护效率。规范化设计通过应用一系列的规范化规则(或称“范式”&a…

Django高级之-forms组件

Django高级之-forms组件 1 校验字段功能 针对一个实例&#xff1a;注册用户讲解。 模型&#xff1a;models.py class UserInfo(models.Model):namemodels.CharField(max_length32)pwdmodels.CharField(max_length32)emailmodels.EmailField()模版文件 <!DOCTYPE html&g…

【死磕Elasticsearch】从实战中来,到实战中去

文章目录 写在前面&#xff1a;1、索引阻塞的种类2、什么时候使用阻塞&#xff1f;场景1&#xff1a;进行系统维护场景。场景2&#xff1a;保护数据不被随意更改场景。场景3&#xff1a;优化资源使用的场景。场景4&#xff1a;遵守安全规则场景。 3、添加索引阻塞API4、解除设置…

HarmonyOS预览功能报错:[webpack-cli] SyntaxError: Unexpected end of JSON input

harmonyos预览功能报错 在使用DevEco Studio写页面&#xff0c;进行预览的时候报错&#xff1a; [Compile Result] [webpack-cli] SyntaxError: Unexpected end of JSON input [Compile Result] at JSON.parse (<anonymous>) [Compile Result] at updateCached…

力扣由浅至深 每日一题.04 最长公共前缀

希望我们都能对抗生活的苦难&#xff0c;在乌云周围突破阴霾积极的生活 —— 24.3.12 14. 最长公共前缀 编写一个函数来查找字符串数组中的最长公共前缀。 如果不存在公共前缀&#xff0c;返回空字符串 ""。 示例 1&#xff1a; 输入&#xff1a;strs ["flower…

psutil, 一个超级有用的Python库

Python的psutil是一个跨平台的库&#xff0c;可以用于获取系统运行时的各种信息&#xff0c;包括CPU使用率、内存使用情况、磁盘和网络信息等。它主要用来做系统监控&#xff0c;性能分析&#xff0c;进程管理。它实现了同等命令行工具提供的功能&#xff0c;如ps、top、lsof、…

20240312-2-贪心算法

贪心算法 是每次只考虑当前最优&#xff0c;目标证明每次是考虑当前最优能够达到局部最优&#xff0c;这就是贪心的思想&#xff0c;一般情况下贪心和排序一起出现&#xff0c;都是先根据条件进行排序&#xff0c;之后基于贪心策略得到最优结果。 面试的时候面试官一般不会出贪…

2024-3-12尾盘一致转分歧

安彩高科开一字符合预期&#xff0c;昨天风光储锂电大涨&#xff0c;理应给大溢价&#xff0c;超预期是 艾艾精工 高开秒板&#xff0c;立航科技高开分歧反核承接良好回封一致&#xff0c;带动了低空经济板块高潮&#xff0c;低空经济开始往 碳纤维 方向扩散。盘中我说了 三晖…

Neo4j 批量导入数据 从官方文档学习LOAD CSV 命令 小白可食用版

学习LOAD CSV&#x1f680; 在使用Neo4j进行大量数据导入的时候&#xff0c;发现如果用代码自动一行一行的导入效率过低&#xff0c;因此明白了为什么需要用到批量导入功能&#xff0c;在Neo4j中允许批量导入CSV文件格式&#xff0c;刚开始从网上的中看了各种半残的博客或者视频…