您现在的位置是:首页 >其他 >go破冰之旅·9·数组与切片(一)网站首页其他

go破冰之旅·9·数组与切片(一)

ProblemTerminator 2023-06-30 16:00:03
简介go破冰之旅·9·数组与切片(一)

 一次5-10分钟即可搞定,实用+效率!

上文中,我们重点看了下函数的常用实践及各种玩法:函数相关

本文开始分为几小节我们来看看go中的数组和切片如何play,因篇幅和效率控制,本文重点看看数组。

目录

数组

数组的变更(数组内容、指针等结合)

数组指针 and 指针数组


数组

数组是一批同数据类型的数据集合,是一个数据列表,它的特点如下:

1,就是存储的所有数据的数据类型都相同,数据类型既可以是内置的类型、也可以是自定义类型;

2,一经创建长度固定;

3,可以通过索引(0、1、2......第一个元素从0开始)来找到对应位置的元素。

下面我们来定义和使用数组:

	// 定义一个整型数组,整型数组的意思就是该数组存放的是整型的数据
	// 先声明,一会用
	var arr0 [2]int
	// len函数可以计算数组、切片、map等结构的长度。
	fmt.Printf("len(arr0)= %v
", len(arr0)) // 长度肯定是0
	// 给arr0数组增加元素:索引为0的位置元素是1,索引为1的位置元素是2
	arr0 = [2]int{1, 2} // 如果设置的元素数量超过2个,则提示Index out of bounds: 2 ,编译都不会通过哦!
	// 看看其中的元素和长度
	fmt.Printf("len(arr0)=%d, arr0: %v
", len(arr0), arr0)

	// 定义一个长度为3的字符串数组并赋值
	var arr1 = [3]string{"A", "B", "C"}
	fmt.Printf("len(arr1)=%d, arr1: %v
", len(arr1), arr1)

	// 如果我不想只声明想直接创建好呢?先创建,一会用
	arr2 := [3]string{}
	arr2[0], arr2[1], arr2[2] = "D", "E", "F"
	fmt.Printf("len(arr2)=%d, arr2: %v", len(arr2), arr2)

speed running:

len(arr0)= 2
len(arr0)=2, arr0: [1 2]
len(arr1)=3, arr1: [A B C]
len(arr2)=3, arr2: [D E F]

数组的变更(数组内容、指针等结合)

为避免多余的汉字干扰,这里将相关的解释和分析过程和代码结合起来,以注释的方式直接镶嵌进去,看起来会更清晰和轻快(每个字母都是作者手打,感谢支持):

	// 如果不想赋所有值,先设置其中一部分呢?定义一个长度为3的字符串数组并赋0号位置的值
	var arr3 = [3]string{"A"}
	fmt.Printf("len(arr3)=%d, arr3: %v
", len(arr3), arr3)
	// 设置索引为1的位置的元素
	arr3[1] = "B"
	fmt.Printf("len(arr3)=%d, arr3: %v
", len(arr3), arr3)
	//arr3[3] = "D"  // 超出数组边界设置,编译不会通过:Invalid array index 3 (out of bounds for 3-element array)

	// 现在有一个长度为3的字符串数组arr4
	var arr4 = [3]string{"A", "B", "C"}
	// 我们直接赋给arr3,arr3的全部数据变为arr4的数据
	arr3 = arr4 // 假设arr4长度设置为2: var arr4 = [3]string{"A"} 则会提示Cannot use 'arr4' (type [2]string) as type [3]string 编译不能通过
	fmt.Printf("len(arr3)=%d, arr3: %v
", len(arr3), arr3)

	// 现在有一个arr5,它指向着arr3的内存地址
	arr5 := &arr3
	// 先看看arr5是什么样、它俩的内存地址以及判断是否相等
	fmt.Printf("len(arr5)=%d, arr5: %v, %p,%p, arr3==arr5: %v
", len(arr5), arr5, &arr3, arr5, arr3 == *arr5)
	// 结果毫无悬念,数据相同,并且arr5保存的地址和arr3指向的地址完全一致,这里要重点注意说辞哦,&arr5和&arr3并不相同。
	// 关于arr3 == *arr5,两者数据和数据类型(长度)完全相同(都引用的是同一快内存的数据),因此==判断为true

	// 此种情况下,我们尝试修改arr5的2号元素的值为new试试
	arr5[2] = "new"
	fmt.Printf("len(arr5)=%d, arr5: %v
", len(*arr5), *arr5) // 注意,这里直接打印arr5也是能直观看到结果的
	fmt.Printf("len(arr3)=%d, arr3: %v
", len(arr3), arr3)   // len(arr3)=3, arr3: [A B new] 两者的索引为2位置的元素均被修改

相信看完上述举例和对应分析,你几乎都知道结果啦,一块展示出来:

len(arr3)=3, arr3: [A  ]
len(arr3)=3, arr3: [A B ]
len(arr3)=3, arr3: [A B C]
len(arr5)=3, arr5: &[A B C], 0xc000076480,0xc000076480, arr3==arr5: true
len(arr5)=3, arr5: [A B new]
len(arr3)=3, arr3: [A B new]

数组指针 and 指针数组

关于数组指针、指针数组这两个概念,许多童鞋会被迷惑,实际就是字面意思并不复杂。

数组指针:你有一个数组,数组指针就是这个数组的指针;

指针数组:你有一个数组,数组内存储的元素都是指针类型的数据。

下面我们同样以典型的案例来予以说明:

	arr0 := [2]int{1, 2}
	// &arr0就是数组的指针,即数组指针,得到的结果就是一个指针地址
	fmt.Printf("%p
", &arr0)

	var a, b = 1, 2
	// arr1存储的是两个int类型变量的地址
	arr1 := []*int{&a, &b}
	fmt.Printf("%v
", arr1) // 其每个元素就是指针地址,并不是真正的数据

	// 那像arr1这种如何看到真实数据呢?
	// 只看其中某个元素,如索引为0的元素时
	fmt.Printf("%v
", *arr1[0])

	// 得到arr1的所有数据时
	for i, data := range arr1 {
		fmt.Printf("index=%v, data=%v, addr=%v
", i, *data, data)
	}

speed running:

0xc0000180b0
[0xc000018098 0xc0000180e0]
1
index=0, data=1, addr=0xc000018098
index=1, data=2, addr=0xc0000180e0

到这里,你应该豁然开朗了哦。

下文我们继续看看数据的其它特征,以及切片的玩法。

风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。