我们之前学习过变量,当存储一个学生名字时可以name=“jack”,但是如果班级有三十人,每个人的名字都想存储到内存中怎么办呢?总不能用三十个变量分别存储吧,这时数组就可以发挥作用了。
数组其实是和字符串一样的序列类型,不同于字符串在内存中连续存储字符,数组用[]的语法将同一类型的多个值存储在一块连续内存中。
声明数组
var 数组名 [元素数量]元素类型
var names [5]string
fmt.Println(names,reflect.TypeOf(names)) // [ ] [5]string
var ages [5]int
fmt.Println(ages,reflect.TypeOf(ages)) // [0 0 0 0 0] [5]int
在计算机语言中数组是非常重要的集合类型,大部分计算机语言中数组具有如下三个基本特性:
一致性:数组只能保存相同数据类型元素,元素的数据类型可以是任何相同的数据类型。
有序性:数组中的元素是有序的,通过下标访问。
不可变性:数组一旦初始化,则长度(数组中元素的个数)不可变。
var x [3]int
var y [5]int
// x y的数据类型相同吗?
数组初始化
var names [5]string
var ages [5]int
names[0] = "张三"
names[1] = "李四"
names[2] = "王五"
names[3] = "赵六"
names[4] = "孙七"
fmt.Println(names) // [张三 李四 王五 赵六 孙七]
ages[0] = 23
ages[1] = 24
ages[2] = 25
ages[3] = 26
ages[4] = 27
fmt.Println(ages) // [23 24 25 26 27]
声明并赋值
var names = [3]string{"张三","李四","王五"}
var ages = [3]int{23,24,25}
fmt.Println(names) // [张三 李四 王五]
fmt.Println(ages) // [23 24 25]
初始化方式: […]不限长度
var names = [...]string{"张三","李四","王五"}
var ages = [...]int{23,24,25}
fmt.Println(names,reflect.TypeOf(names)) // [张三 李四 王五] [3]string
fmt.Println(ages,reflect.TypeOf(ages)) // [23 24 25] [3]int
初始化方式:索引设置
var names = [...]string{0:"张三",2:"王五"}
fmt.Println(names) // [张三 王五]
基于索引访问和修改数组元素
var names = [...]string{"张三","李四","王五","赵六","孙七"}
// 索引取值
fmt.Println(names[2])
// 修改元素值
names[0] = "zhangsan"
fmt.Println(names)
// 切片取值
fmt.Println(names[0:4])
fmt.Println(names[0:])
fmt.Println(names[:3])
// 循环取值
for i:=0;i<len(names);i++{
fmt.Println(i,names[i])
}
for k,v := range names{ // range 表达式是副本参与循环
fmt.Println(k,v)
}
练习
func 第1步_声明数组1() {
//先声明再赋值
//var 数组名[元素数量]元素类型
var age [3]int
fmt.Println(age)
var names [5]string
names[0] = "jack"
fmt.Println(names)
//数组的声明并赋值
var names1 = [3]string{"jj", "haha"}
fmt.Println(names1)
var ages = [3]int{122, 456, 347}
fmt.Println(ages)
//数组省略长度赋值
var names2 = [...]string{"小涛", "小光"}
fmt.Println(names2)
//索引赋值
var names3 = [...]string{0: "yuan", 2: "rains"}
fmt.Println(names3)
fmt.Println(len(names3))
}
func 第2步_数组的声明赋值索引操作() {
var names = [5]string{"yuan", "rain", "alvin"}
fmt.Println(names)
//索引操作
names[2] = "Alive"
fmt.Println(names)
}
func 第3步_数组的切片操作() {
var arr = [5]int{1, 2, 34, 5, 6}
//切片操作,数组[start索引:end索引]
ints := arr[1:3]
//[]int,这就是切片了,没有长度
fmt.Println(ints, reflect.TypeOf(ints))
}
func 第4步_遍历数组() {
var arr = [5]int{1, 2, 33, 77, 99}
//三要素for循环
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
}
func 第5步_range循环() {
var arr = [5]int{1, 2, 33, 77, 99}
for i, v := range arr {
fmt.Println(i, v)
}
}
func 第6步_构建切片方式1() {
//构建切片方式1,通过数组切片操作获得切片对象
var arr = [3]string{"rain", "eric", "alvin"}
fmt.Println(arr, reflect.TypeOf(arr))
s1 := arr[0:2]
fmt.Println(s1, reflect.TypeOf(s1))
s2 := arr[1:]
fmt.Println(s2, reflect.TypeOf(s2))
s2[0] = "Yuan"
fmt.Println(s1)
fmt.Println(arr)
}
func 第7步_构建切片方式2() {
//切片是对数组的引用
var a = [5]int{1, 2, 3, 4, 5}
slice := a[:] //起始地址 长度 容量
fmt.Printf("slice切片的长度:%d,容量:%d\n", len(slice), cap(slice))
fmt.Println(slice) //[1 2 3 4 5]
newSlice := slice[1:3]
fmt.Println(newSlice) //[2 3]
newSlice[1] = 1000
fmt.Println(newSlice) //[2 1000]
fmt.Println(slice) //[1 2 1000 4 5]
}
func 第8步_直接声明切片() {
s := []int{10, 11, 12, 13, 14}
s1 := s[1:4]
//11,12,13,长度?容量?3 4
fmt.Println(s1, len(s1), cap(s1))
//12
s3 := s1[1:2]
//长度是1,容量是3
fmt.Println(s3, len(s3), cap(s3))
}
func 第9步_练习题() {
/**
type Slice struct {
Data uintptr // 指针,指向底层数组中切片指定的开始位置
Len int // 长度,即切片的长度
Cap int // 最大长度(容量),也就是切片开始位置到数组的最后位置的长度
}
*/
var a = [...]int{1, 2, 3, 4, 5, 6}
a1 := a[0:3]
a2 := a[0:5]
a3 := a[1:5]
a4 := a[1:]
a5 := a[:]
a6 := a3[1:2]
fmt.Printf("输出结果%d,a1的长度%d,容量%d\n", a1, len(a1), cap(a1)) //1, 2, 3 长度:3,容量:6
fmt.Printf("输出结果%d,a2的长度%d,容量%d\n", a2, len(a2), cap(a2)) //1, 2, 3, 4, 5 长度:5,容量:6
fmt.Printf("输出结果%d,a3的长度%d,容量%d\n", a3, len(a3), cap(a3)) //2, 3, 4, 5 长度:4 容量:5
fmt.Printf("输出结果%d,a4的长度%d,容量%d\n", a4, len(a4), cap(a4)) //2, 3, 4, 5, 6,长度:5 容量:5
fmt.Printf("输出结果%d,a5的长度%d,容量%d\n", a5, len(a5), cap(a5)) //1, 2, 3, 4, 5, 6 长度:6 容量:6
fmt.Printf("输出结果%d,a6的长度%d,容量%d\n", a6, len(a6), cap(a6)) //3 ,长度:1,容量:4
}
func 第10步_练习题1() {
s1 := []int{1, 2, 3}
s2 := s1[1:] //2, 3
s2[1] = 4
fmt.Println(s1) // 1,2,4
}
func 第11步_练习题2() {
var a = []int{1, 2, 3}
b := a //引用拷贝
a[0] = 100
fmt.Println(b) //100,2,3
}
func 第12步_make函数1() {
//初始化创建空间,开辟空间
var s = make([]int, 5, 10)
s[0] = 100
fmt.Println(s, reflect.TypeOf(s))
fmt.Println(len(s), cap(s))
}
func 第13步_练习题11() {
a := make([]int, 5)
b := a[0:3] //0,0,0
a[0] = 100
fmt.Println(a) //100,0,0,0,0
fmt.Println(b) //100,0,0
}
func 第14步_append函数使用() {
var s []int
s1 := append(s, 1)
fmt.Println(s1)
s2 := append(s1, 2, 3, 4)
fmt.Println(s2)
var t = []int{5, 6, 7}
s3 := append(s2, t...)
fmt.Println(s3)
}
func 第15步_append函数使用1() {
s := make([]int, 3, 10)
s5 := append(s, 100)
fmt.Println(s5) //[0 0 0 100]
}
func 第16步_append扩容机制容量不够2倍扩容() {
//append扩容机制容量不够2倍扩容
a := []int{11, 22, 33}
fmt.Println(len(a), cap(a)) //3 3
c := append(a, 44)
a[0] = 100
fmt.Println(a) //[100 22 33]
fmt.Println(c) //[11 22 33 44]
}
func 第17步_容量够了不需要扩容了() {
a := make([]int, 3, 10)
fmt.Println(a) //0,0,0
b := append(a, 11, 22)
fmt.Println(a) //0,0,0
fmt.Println(b) //0,0,0,11,22
a[0] = 100
fmt.Println(a) //100,0,0
fmt.Println(b) //100,0,0,11,22
}
func 第18步_经典面试题() {
arr := [4]int{10, 20, 30, 40}
s1 := arr[0:2] //10,20
s2 := s1
//10,20,1,2,3
s3 := append(append(append(s1, 1), 2), 3)
s1[0] = 1000
fmt.Println(s1) //1000,20
fmt.Println(s2) //1000,20
fmt.Println(s3) //10,20,1,2,3
fmt.Println(arr) //1000, 20, 1, 2
}
func 第19步_切片的地址是否一致() {
var s = []int{1, 2, 3}
fmt.Printf("%p\n", &s)
s = append(s, 4)
fmt.Printf("%p\n", &s)
}
func 第20步_向开头插入() {
//向开头插入值或者切片
var a = []int{1, 2, 3}
ints := append([]int{0}, a...)
fmt.Println(ints)
}
func 第21步_任意位置插入() {
var b = []int{1, 2, 3, 4, 5}
var i = 2
bb := append([]int{100}, b[i:]...)
cc := append(b[:i], bb...)
fmt.Println(cc)
}
func 第22步_删除元素() {
var c = []int{1, 2, 3, 4, 5}
c = append(c[:2], c[2+1:]...)
fmt.Println(c)
}