golang未初始化的slice和初始化为空的slice的区别简析

本文详细探讨了Golang中切片的三种常见定义方式,包括未初始化的slice、字面量定义和`make`函数创建的空slice,并揭示了它们的底层指针机制。通过实例展示了切片的不同特性,如nil值、长度和容量,以及在实际应用中的行为和优化建议。
摘要由CSDN通过智能技术生成

先看两种形式的slice定义

// 定义未初始化的slice
var s1 []string

// 通过字面量形式定义并初始化为空slice
var s2 = []string{}

// 通过make函数定义并初始化为空slice
var s3 = make([]string, 0, 0)

我们知道,在golang中切片是对底层数组中的连续一部分存储空间的引用,是类似一种数组指针的存在,例如我们可以直接像打印一个指针所指向的地址的形式来打印切片

	// 先来看%p 打印格式的用法
	var arr = [...]string{"aaa"}
	fmt.Printf("%p\n", arr)  // 输出 %!p([1]string=[aaa]),指示这并不是一个指针
	fmt.Printf("%p\n", &arr) // 正常输出地址 0xc0001021e0
	
	fmt.Printf("s1: %p, s2: %p, s3: %p\n", s1, s2, s3)  //输出s1: 0x0, s2: 0x119f408, s3: 0x119f408  说明在golang中slice的底层就是指针,s1的值其实就是nil
	
	if s1 == nil {
		fmt.Println("s1 yes")   // 输出 s1 yes
	}
	if s2 == nil {
		fmt.Println("s2 yes")   // 没输出
	}
	if s3 == nil {
		fmt.Println("s3 yes")   // 没输出
	}

从上面可以看出,s1没有具体指向的内存空间, 而s2和s3都指向了具体的内存空间,这就是它们的最大区别,而s2和s3没有区别,只是两种不同的书写形式罢了。其实以上三种形式在golang代码中的使用基本上是没有什么区别的,例如

	fmt.Println(s1, s2, s3) //[] [] []
	fmt.Println(len(s1), cap(s1), len(s2), cap(s2), len(s3), cap(s3)) //0 0 0 0 0 0
	
	for i, v := range s1 {
		fmt.Println(i, v)
	}  // 没报错,没有输出

	for i, v := range s2 {
		fmt.Println(i, v)
	} // 没报错,没有输出

	for i, v := range s3 {
		fmt.Println(i, v)
	} // 没报错,没有输出

	s1 = append(s1, "s1s1")
	s2 = append(s2, "s2s2")
	s3 = append(s3, "s3s3")
	fmt.Println(s1, s2, s3) // [s1s1] [s2s2] [s3s3]

	s1 = s1[:]  // 不报错
	s2 = s2[:]  // 不报错
	s3 = s3[:]  // 不报错

	func Print(s... string) {
		if len(s) > 0 {
			fmt.Println(s[0])
		} else {
			fmt.Println("[]")
		}
	}
	Print(s1...) // 不报错
	Print(s2...) // 不报错
	Print(s3...) // 不报错

所以,在正常的使用过程中,如果无法预知slice的大小需要一个空的slice,使用s1的形式是没有问题的,而且能减少一次不必要的内存分配

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值