Golang(四)[复合数据类型]

复合数据类型——数组和结构体——是通过组合简单类型,来表达更加复杂的数据结构。

1.数组(array)

1.简介

  • 数组是一个具有相同数据类型的元素组成的固定长度有序序列
  • 数组是值类型长度是类型的组成部分,意味着[10]int和[20]int是完全不同的两种数组类型。
  • 数组元素通过索引(位置)来读取(或者修改),索引从 0 开始,第一个元素索引为 0,第二个索引为 1,以此类推,最后一个元素为【数组元素个数-1】。
  • 同类型的两个数组支持”==”和”!=”比较,但是不能比较大小
  • 数组作为参数时,函数内部不改变数组内部的值,除非是传入数组的指针
  • 数组长度最大为 2Gb
  • 注意:

1.指针数组:

[3]*int

2.数组指针:

*[3]int

数组

2.定义

Go 语言数组声明需要指定元素类型及元素个数:

var array_name [size]data_type
释义:
array_name:数组名称
size:数组长度/大小,数组的长度/大小只能是整型【int】数,且必须是数值类型
data_type:数据类型

当定义完成数组后,就在内存中开辟了size个连续的存储空间,每个数据都存储在相应的空间内,数组中包含的每个数据被称为数组元素(element),一个数组包含的元素个数被称为数组的长度,未赋值的数组元素的值为数组类型的零值,如果是整型是0,字符串是空字符,浮点型数据是0,而不是0.0,interface{}类型的是nil
数组初始化未赋值时候的类型零值

3.初始化

定义数组的时候初始化数据,没有初始化的元素为类型零值
var array_name [size]data_type = [size]data_type{data1,data2,data3}
或者:
var array_name = [size]data_type{data1,data2,data3}
亦或者:
array_name := [size]data_type{data1,data2,data3}
或者使用自动计算长度:
array_name := [...]data_type{data1,data2,data3}
或者先定义,后赋值
var array_name = [size]data_type
array_name[0] = 1
array_name[1] = 2
array_name[2]  = 3

数组的初始化

4.访问

数组可以通过下标进行访问,下标是从0开始,最后一个元素是len-1

访问数组元素:
array_name[index]

数组的访问

5.遍历

5.1.索引遍历

索引范围为:0len(array)-1

for index := 0; index < len(array_name); index++{
......
}

使用索引从 0 到 len(数组)-1遍历数组

5.2.range遍历

for index,value:=range array_name{
......
}

使用范围range进行遍历数组

6.越界

如果下标在数组合法范围之外,就会触发越界,访问越界不会编辑通过,不会打印;访问越界会引发panic异常

6.1.正向越界

1.访问/修改正向越界
array_name[size]

2.遍历正向越界
for index := 0;index <= len(array_name); index++{
......
}

修改数组下标越界
数组正向越界访问数组
遍历越界会引发panic异常

6.2.反向越界

1.访问/修改反向越界
array_name[-1]

2.遍历反向越界
for index := -1;index < len(array_name); index++{
......
}

反向越界
反向遍历

7.数组指针

*[size]data_type

数组指针,本质是一个指针
数组指针是指向数组地址的指针
数组指针

8.指针数组

[size]*data_type

指针数组,本质是一个数组
指针数组存放的是指针的数组
指针数组

9.函数参数传递

数组作为函数参数传递时,是进行的值拷贝,不是引用传递
Go语言中本质上并没有引用传递,做的是值传递,如果是普通数组,则是copy了一份数组进行操作,如果是指针类型数组,则copy的是地址值

func main() {
	var array = [10]int{1, 2, 3, 4, 5}
	test1(array)
	fmt.Println(array)
}
// 数组作为函数参数
func test1(arr [10]int) {
	arr[0] = 100
}

数组作为函数参数---值传递
数组作为函数参数,是值传递,不会改变数组元素的值
把一个大数组传递给函数会消耗很多内存,可以通过:

  1. 传递数组的指针
  2. 使用数组的切片

避免消耗过多的内存

如果需要实现引用传递,就需要进行数组指针作为函数参数
Go语言中本质上并没有引用传递,做的是值传递,如果是普通数组,则是copy了一份数组进行操作,如果是指针类型数组,则copy的是地址值
数组指针作为函数参数

数组是值类型,因此改变副本的值,不会改变本身的值

10.比较[==或!=]

如果一个数组的元素类型是可以相互比较的,那么数组类型也是可以相互比较的,可以直接通过 == 比较运算符来比较两个数组,只有当两个数组的所有元素都是相等的时候数组才是相等的。不相等比较运算符 != 遵循同样的规则。

func main() {
	a := [2]int{1, 2}
	b := [...]int{1, 2}
	c := [2]int{1, 3}
	fmt.Println(a == b, a == c, b == c) // "true false false"
	//d := [3]int{1, 2}
	//fmt.Println(a == d) // 编译错误:无法比较 [2]int == [3]int
}

在这里插入图片描述

11.斐波那契数列

使用数组实现斐波那契数列

 //菲波那切数列,非递归方式实现,打印前50个数
func fab() {
	var a [50]uint64
	a[0] = 1
	a[1] = 1
	for i := 2; i < 50; i++ {
		a[i] = a[i-1] + a[i-2]
	}
	for _, v := range a {
		fmt.Println(v)
	}
}
func main() {
	fab()
}

12.底层实现

数组的底层是一个连续的内存地址空间,内存的最小单元是字节
数组的底层是一个连续的内存地址空间
对数组和数组的元素取地址

13.len( )

len(array_name)用来计算数组的长度/大小
len( )

14.cap( )

cap(array_name)可以获得 和len( array_name)同样的效果,获取数组的长度
cap( )可以获取数组的长度/大小

15.多维数组

Go 语言支持多维数组,常用的多维数组声明方式:

var array_name[SIZE1][SIZE2]...[SIZEN] data_type

二维数组是最简单的多维数组,二维数组本质上是由一维数组组成的。二维数组定义方式:

var array_name [ x ][ y ] data_type
释义:
data_type: Go 语言的数据类型,array_name为数组名,二维数组可认为是一个表格,x 为行,y 为列
func main() {
	var array = [2][5]int{
		{1,2,3,4,5},
		{6,7,8,9,10},
	}
	for index, _ := range array {
		for key, _ := range array[index] {
			fmt.Printf("&array[%d][%d] = %p\n",index,key,&array[index][key])
		}
	}
}

二维数组代码
二维数组内存图解

16.元素反转/逆置

func main() {
	var array = [...]int{
		1, 2, 3, 4, 5, 6, 7, 8, 9, 10,11,
	}
	fmt.Println("逆序前:",array)
	// 使用数组指针进行参数传递
	reverse(&array)
	fmt.Println("逆序后:",array)
}
func reverse(arr *[11]int) {
	// 对半进行交换
	for i := 0; i < len(arr)/2; i++ {
		arr[i],arr[len(arr)-1-i]  = arr[len(arr)-1-i],arr[i]
	}
}

数组逆置

17.注意事项

  1. 数组是多个相同类型数据的序列,一个数组一旦声明/定义了,其长度是固定的,不能动态变化。
  2. 数组中的元素可以是任何数据类型,包括值类型和引用类型,但是不能混用。
  3. 数组创建后,如果没有赋值,有默认值
    数值类型数组:默认值为0
    字符串类型数组:默认值为""
    bool数组: 默认值为false
    指针数组: 默认值nil
  4. 使用数组的步骤:
    1.声明数组并开辟空间
    2.给数组各个元素赋值
    3.使用数组
  5. 数组的下标从0开始
    数组下标必须在指定范围内使用,否则报panic:数组越界
  6. Go的数组属于值类型 ,在默认情况下是值传递,因此会进行值拷贝。数组间不会相互影响
  7. 如果想在其它函数中,去修改原来的数组,可以使用引用传递(指针方式)
  8. 长度是数组类型的一部分,在传递函数参数时,需要考虑数组的长度
  9. new([size]data_type)方式生成的是数组指针不是数组
  10. 不可以通过make方式来创建数组
    new方式创建爱你的是数组指针,不能通过make创建数组
  11. 特殊:
// 这样定义数组也是合法的
var array = [3]int{1,2,3,}// 可以在最后一个元素后面跟逗号

2.结构体

结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。
1.每个字段称为结构体的成员。通常也被称为属性。
2.结构体对应绑定的方法,通常被称为结构体的行为。

发布了48 篇原创文章 · 获赞 14 · 访问量 4153

猜你喜欢

转载自blog.csdn.net/weixin_42366378/article/details/105102767