Go数组和切片

目录

一、数组

1、数组的声明

2、循环数组

3、数组截取

二、切片

1、切片的内部结构

2、声明切片

3、切片的可变长原理

4、切片共享存储结构

5、切片是否可以进行比较

三、数组和切片的异同


一、数组

1、数组的声明

package array

import "testing"

//数组初始化
func TestArrayInit(t *testing.T)  {
	//声明并初始化默认值为0
	var a [3]int

	//声明同事初初始化一维数组
	b := [3]int{1, 2, 3}
	//声明同时初始化二维数组
	c := [2][2]int{{1, 2}, {3, 4}}
	//不指定数组长度,用三个点代替,go会自动帮我们初始化到对应的长度
	d := [...]int{1,2,3,4,5}

	t.Log(a[0], b[1], c[0][1], d[0])
}

2、循环数组

package array

import "testing"

//循环数组
func TestArrayTravel(t *testing.T) {
	var arr = [3]int{1, 2, 3}

	//使用 for 循环数组(不推荐)
	for i := 0; i < len(arr); i++ {
		t.Log(arr[i])
	}

	//使用 range 关键字循环数组(推荐),类似于php里面的 foreach
	for idx, v := range arr {
		t.Log(idx, v)
	}

	//如果不想用 idx ,可以使用 '_' 做缺省值。不能不写
	for _, v := range arr {
		t.Log(v)
	}
}

//循环二维数组
func Test2DimensionalArrayTravel(t *testing.T) {
	var arr = [2][2]int{{1, 2}, {3, 4}}

	for _, val := range arr {
		for k, v := range val {
			t.Log(k, v)
		}
	}
}

3、数组截取

a[开始索引(包含),结束索引(不包含)]

package array

import "testing"

//数组截取
func TestArraySection(t *testing.T){
	arr := [...]int{0, 1, 2, 3, 4}
	//截取数组,从 arr[1] 开始到 arr[2]结束 ,但不包含 arr[2]
	t.Log(arr[1:2])			//[1]
	//截取数组,从 arr[1] 开始到 arr[3]结束 ,但不包含 arr[3]
	t.Log(arr[1:3])			//[1 2]
	//截取数组,从 arr[1] 开始到数组的结尾
	t.Log(arr[1:len(arr)])	//[1 2 3 4]
	//截取数组,从 arr[1] 开始到数组的结尾另一种写法
	t.Log(arr[1:])			//[1 2 3 4]
	//截取数组,从数组的第一个元素开始到 arr[3] ,但不包含 arr[3]
	t.Log(arr[:3])			//[0 1 2]
}

二、切片

1、切片的内部结构

也是一个连续的数据存储结构,用起来的感觉像一个可变长的数组,但是如果从内部分析,它和数组还是不一样,它的结构如下:

2、声明切片

package slice

import "testing"

//声明切片
func TestSliceStatement(t *testing.T){
	//用 var 声明一个切片,后面不要加 {}
	var s0 []int
	//查看切片长度和容量的变化
	t.Log(len(s0), cap(s0))		//0, 0

	//如果需要往切片追加元素,用 append() 函数
	s0 = append(s0, 1)
	t.Log(len(s0), cap(s0))		//1, 1

	//用 := 推导的方式声明一个切片,后面需要加 {}, 初始值为 0
	s1 := []int{}
	t.Log(len(s1), cap(s1))		//0, 0

	//声明一个切片并赋初值
	s2 := []int{1, 2, 3, 4}
	t.Log(len(s2), cap(s2))		//4, 4

	//用 make() 函数来定义一个切片(推荐)
    //在 Go 语言中创建某一种类型的变量,我们经常会用到 make()
	s3 := make([]int, 3, 5)
    //此处我们发现切片的长度和容量是不一样的
	t.Log(len(s3), cap(s3))		//3, 5
}
package slice

import "testing"

//切片初始化
func TestSliceInit(t *testing.T)  {
	//这里我们将切片的长度和容量设置为不一样长。
	s3 := make([]int, 3, 5)
	t.Log(len(s3), cap(s3))		//3, 5

	//因为我们长度定义的长度为 3,Go 就只给我们初始化了 3 个值,如果想访问第四个元素就会报错
	t.Log(s3[0], s3[1], s3[2], s3[3]) //index out of range [3] with length 3
}
package slice

import "testing"

//切片初始化
func TestSliceInit(t *testing.T)  {
	//这里我们将切片的长度和容量设置为不一样长。
	s3 := make([]int, 3, 5)
	t.Log(len(s3), cap(s3))		//3, 5

	s3 = append(s3, 3)
	t.Log(len(s3), cap(s3))		//4, 5
	t.Log(s3[3])				// 1
}

3、切片的可变长原理

package slice

import "testing"

//切片长度的变化情况
func TestSliceGrowing(t *testing.T){
	s :=[]int{}
	for i :=0; i < 10; i++ {
		s = append(s, i)
		t.Log(len(s,), cap(s))
	}
}

结论切片的增长规律为,当切片的长度增大到容量的最大值时,切片的容量会两倍的增加。

这样解释了为什么 append() 函数需要写成 s = append(s, 1),而不是 append(s, 1) 了,因为当切片的存储空间变大后,是重新获取了一块儿连续的存储空间,故需要重新赋值。

4、切片共享存储结构

package slice

import "testing"

//切片存储空间是共享的
func TestShareMenory(t *testing.T){
	year := []string{"Jay", "Feb", "Mar", "Apr", "May", "Jun", "Juy", "Aug", "Sep", "Oct", "Nov", "Dec"}

	//获取 Q2 季度的月份
	Q2 := year[3:6]
	t.Log(len(Q2), cap(Q2))			//3, 9
	t.Log(Q2)						//[Apr May Jun]

	//获取夏天的月份
	summer := year[5:8]
	t.Log(len(summer), cap(summer))	//3, 7
	t.Log(summer)					//[Jun Juy Aug]

	//将 summer 切片中的的第一个元素改成 Unknown
	summer[0] = "Unknown"

	//我们会发现 Q2 切片中的元素也被修改了
	t.Log(Q2)						//[Apr May Unknown]
}

结论:切片的存储空间是共享的。

5、切片是否可以进行比较

package slice

import "testing"

//切片是否可进行比较
func TestSliceComparing(t *testing.T) {
	s1 := []int{1, 2, 3, 4}
	s2 := []int{1, 2, 3, 4}

	//这里会报错 slice can only be compared to nil
	if s1 == s2 {
		t.Log("yes")
	} else {
		t.Log("no")
	}
}

结论切片之间不能进行比较。

三、数组和切片的异同

  1. 数组容量是固定的,切片的容量可伸缩。
  2. 数组间是可进行比较的,而切片不行。

:这篇博文是我学习中的总结,如有转载请注明出处:https://blog.csdn.net/DaiChuanrong/article/details/117767982

上一篇Go循环、判断和switch

下一篇Go数据类型

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值