作者:秃秃爱健身,多平台博客专家,某大厂后端开发,个人IP起于源码分析文章 😋。
源码系列专栏:Spring MVC源码系列、Spring Boot源码系列、SpringCloud源码系列(含:Ribbon、Feign)、Nacos源码系列、RocketMQ源码系列、Spring Cloud Gateway使用到源码分析系列、分布式事务Seata使用到源码分析系列、JUC源码系列
基础系列专栏:30天熟悉GO语言(建设中)
码文不易,如果感觉博主的文章还不错,请点赞👍、收藏 ⭐️支持一下博主哇 🙏
联系方式:Saint9768,加我进技术交流群,一起学习进步📚、freedom✈️🌊
文章目录
- 一、前言
- 二、数组
- 1、数组定义
- 2、数组初始化
- 1)使用数组字面量初始化数组
- 2)GO自动计算数组的长度
- 3)指定特定元素的值
- 3、数组内存分析
- 4、数组使用
- 1)访问数组元素
- 2)同类型数组赋值
- 3)将数组按引用传递
- 5、数组遍历
- 三、二维数组
- 1、定义&赋值
- 2、初始化
- 四、总结
一、前言
Go系列文章:
- GO开篇:手握Java走进Golang的世界
- 2 Go开发环境搭建、Hello World程序运行
- 3 Go编程规约和API包
- 4 Go的变量、常量、运算符
- 5 Go 基本数据类型
- 6 Go 复杂数据类型之指针
- 7 Go流程控制之分支结构if、switch
- 8 Go流程控制之循环结构for range、goto、break、continue
- Go函数全方位解析
- Go异常处理机制
Go专栏传送链接:https://blog.csdn.net/saintmm/category_12326997.html
二、数组
在GO语言中,数组是一个长度固定的数据类型,用于存储相同类型的数据
1、数组定义
数组声明时需要指定内部存储的数据的类型,需要存储的元素的数量。数组声明完成之后,每个数组元素的默认值都是对应类型的零值。
数组定义格式:var arrayName [数组大小]数据类型
例如:声明一个包含3个元素的整型数组。
var array 3[int]
2、数组初始化
数组的初始化有三种方式:使用数组字面量、自动计算数组长度、指定特定索引位置元素的值。
1)使用数组字面量初始化数组
初始化一个包含3个元素的整型数组
var arr1 [3]int = [3]int{3,6,9}
fmt.Println(arr1)
或:
var arr2 = [3]int{1,2,3}
fmt.Println(arr2)
2)GO自动计算数组的长度
使用...
代替数组的长度,GO会根据初始化时数组元素的数量来确定该数组的长度。
arr3数组的长度为4。
var arr3 = [...]int{1,3,5,7}
fmt.Println(arr3)
3)指定特定元素的值
在已知数组长度的前提下,可以给数组的特定索引位置指定具体的值。
下面初始化一个长度为3的数组,并乱序指定索引0和索引2位置的元素值分别为3,9。
var arr4 = [...]int{2:9, 0:3}
fmt.Println(arr4)
3、数组内存分析
数组开辟的内存空间是一块连续的内存空间,其访问/修改效率很高。
示例:
package main
import "fmt"
func main() {
// 定义数组
var arr [3]int32
// 打印数组
fmt.Println(arr)
// arr的内存地址值
fmt.Printf("arr的地址为:%p", &arr)
fmt.Println()
// arr[0]内存地址值
fmt.Printf("arr[0]的地址为:%p", &arr[0])
fmt.Println()
// arr[1]内存地址值
fmt.Printf("arr[1]的地址为:%p", &arr[1])
fmt.Println()
// arr[2]内存地址值
fmt.Printf("arr[2]的地址为:%p", &arr[2])
}
输出:
内存使用解析:
示例中 int32类型的数组arr,内存地址为0xc00001a0c0,则arr[n]的内存地址为 0xc00001a0c0 + 4*n
4、数组使用
1)访问数组元素
要访问数组里的某个元素,使用[]
运算符。
package main
import "fmt"
func main() {
arr1 := [3]int{1,2,3}
fmt.Println("arr1[0]的值为:", arr1[0])
}
输出:
2)同类型数组赋值
可以把同样类型的一个数组赋值给另外一个数组。
// 声明一个包含3个元素的整型数组
var arr [3]int32
arr1 := [3]int32{1,2,3}
// 把arr1的值赋值给arr
arr = arr1
注意:数组长度属于类型的一部分,即:数组变量的类型包括两步分:数组长度和每个元素的类型,只有这两部分都相同的数组,才是类型相同的数组,才能互相赋值。
package main
import "fmt"
func main() {
arr1 := [3]int{1,2,3}
fmt.Printf("arr1数组的类型为:%T\n", arr1)
arr2 := [6]int{1,2,3,4,5,6}
fmt.Printf("arr2数组的类型为:%T\n", arr2)
}
从输出来看:arr1和arr2的类型分别为[3]int、[6]int。
此外,编译器会阻止类型不同的数组互相赋值。
3)将数组按引用传递
在go中数据属于值类型,默认情况下按值传递,将数组作为参数在函数之间传递时,会进行值拷贝;
package main
import "fmt"
func main() {
arr1 := [3]int{1,2,3}
// 数组默认按值传递,函数不会改变arr1的元素值
changeArrayValue(arr1)
fmt.Println("arr1数组为:", arr1)
}
func changeArrayValue(arr [3]int) {
arr[0] = 7
}
输出:
- 从输出内容可以得知,函数间默认传递数据的方式是按值传递;在子函数(
changeArrayValue
)中修改数组,不会影响父函数(main
)中数组的值。
根据内存和性能来看,在函数见传递数组是一个开销很大的操作。因此我们可以选择使用指针在函数间传递数组。
package main
import "fmt"
func main() {
arr1 := [3]int{1,2,3}
// 使用指针的方式做引用传递,函数会改变arr1的元素值
changeArrayValueByPointer(&arr1)
fmt.Println("arr1数组为:", arr1)
}
func changeArrayValueByPointer(arr *[3]int) {
arr[0] = 7
}
输出:
- 将数组以指针的方式传递时,数组都指向同一组数据,子函数中修改数组的元素值,父函数中可以感知到。
5、数组遍历
两种遍历方式:普通for循环、for range。
示例:
package main
import "fmt"
func main() {
// 定义数组
var scores [4]int
scores[0] = 99
scores[1] = 97
scores[2] = 89
scores[3] = 91
// 遍历数组
// 方法一:普通for循环
for i :=0; i< len(scores); i++ {
fmt.Println(scores[i])
}
fmt.Println()
// 方法二:for range
for key,value := range scores {
fmt.Printf("第%d个学生的成绩的为:%d\n", key, value)
}
}
输出:
三、二维数组
二维数组、乃至多维数组,本质上只是一维数组中的元素值变成了数组,故多维数组的特性和一维数组保持一致。二维数组的遍历也是两种方式:普通for循环、for range。
此处我们介绍一下二维数组的声明、初始化。
1、定义&赋值
package main
import "fmt"
func main() {
// 定义数组
var arr [2][3]int32
fmt.Println(arr)
fmt.Printf("arr的地址为:%p\n", &arr)
fmt.Printf("arr[0]的地址为:%p\n", &arr[0])
fmt.Printf("arr[0][0]的地址为:%p\n", &arr[0][0])
fmt.Printf("arr[1]的地址为:%p\n", &arr[1])
fmt.Printf("arr[1][0]的地址为:%p\n", &arr[1][0])
// 赋值
arr[0][1] = 12
}
2、初始化
初始化方式和一维数组一样
// 使用数组字面量初始化数组
var arr1 [2][3]int32 = [2][3]int32{{1,2,3},{4,5,6}}
fmt.Println(arr1)
四、总结
本文内容从数组的定义、初始化 到 数组使用 以及 数组的内存分析。
数组的初始化方式有三种:数组字面量、不定长数组、指定特定元素值;数组的同类型是指两个数组长度相等、元素值类型相等。
另外,数组默认是按值传递,可以使用传递数组指针的方式实现按引用传递。