go语言基础之数组
Array
数组是同一种数据类型的集合,Go语言中,数组从声明时就确定,使用时可以修改数组成员,数组的大小不可以变化。
数组是值类型,,将数组赋值给另一个变量,就相当于复制了一份,就变成了两个数组,两个数组之间的操作不冲突
注意:数组支持==和!=操作,因为数组是值类型
package main
import "fmt"
func main() {
//数组
//存放元素的容器
//必须指定数组存放的类型和容量
//数组的长度是数组类型的一部分
var ar [3]int
fmt.Printf("%T", ar)
//数组的初始化
//如果我们不初始化数组,那么数组里的元素默认都是二进制的零值(bool:false int和flaot:0 string:"")
//初始化方式1
ar = [3]int{
1, 2, 3}
fmt.Printf("%v\n", ar)
//初始化方式2
//根据初始值自动推断数组的长度
arr := [...]int{
1, 2, 3, 4, 5, 6}
fmt.Printf("%v\n", arr)
//初始化方式3
//根据索引初始化
array := [3]int{
1: 1, 2: 1}
fmt.Printf("%v\n", array)
//遍历数组
for i := 0; i < len(arr); i++ {
fmt.Println(arr[i])
}
for i, v := range arr {
fmt.Printf("%d--%d\n", i, v)
}
//多维数组
var ar1 [3][2]int
ar1 = [3][2]int{
[2]int{
1, 2},
[2]int{
3, 4},
[2]int{
5, 6},
}
fmt.Println(ar1)
//遍历多维数组
for _, v := range ar1 {
for _, v1 := range v {
fmt.Println(v1)
}
}
切片(slice)
切片是一个拥有相同数据类型元素的,可变长度的序列,他是基于数组类型做的一个封装,它非常灵活,支持自动扩容,切片是一个引用类型,他的内容结构包含地址,长度和容量,切片用于快速操作一块数据集合。
package main
import "fmt"
func main() {
//切片的定义
var slice []int
//切片的初始化
slice = []int{
1, 2, 3, 4, 5, 6, 7}
fmt.Println(slice)
//数组的长度和数组的容量
fmt.Println(len(slice))
fmt.Println(cap(slice))
//数组的切片,得到一个切片类型
array := [...]int{
1, 2, 3, 4, 5, 6, 7, 8, 9}
arrsl := array[0:4] //数组的切片
//切片的容量是指底,切片的第一个元素,到底层数组的最后一个元素
//比如,切片是[3:],那么切片的容量就是len(array)-3
fmt.Printf("%T--%v--%d\n", arrsl, arrsl, cap(arrsl))
//切片是引用类型,他都指向了底层的一个数组,数组发生改动,那么切片也发生改动
array[1] = 200
fmt.Println(arrsl)
}
使用make()函数构造切片。
package main
import "fmt"
func main() {
//使用make()函数构造一个切片,参数1切片的类型,参数2切片的长度,参数3切片容量
me := make([]int, 5, 10)
fmt.Printf("%T--%d--%d", me, len(me), cap(me))
}
切片的本质
切片就是一个框,框住了一块连续的内存,这块内存只能存储想同类型的值
切片不能直接比较
切片之间是不能比较的,我们不能使用==操作符来判断两个切片的元素是否相同,切片的唯一合法比较适合nil进行比较,一个nil值得切片是没有底层数组的,一个nil值得切片的长度和容量都是0,但是我们不能说一个长度和容量都是0的切片是nil,所以判断切片是否为空,用len(s) == 0判断,不应该用s == nil判断。
package main
import "fmt"
func main() {
me := make([]int, 0)
fmt.Printf("%T--%d--%d", me, len(me), cap(me))
}
切片的赋值与遍历
package main
import "fmt"
func main() {
me := make([]int, 0)
fmt.Printf("%T--%d--%d\n", me, len(me), cap(me))
//切片的赋值
s1 := []int{
1, 2, 3}
s2 := s1
s2[1] = 1000
fmt.Printf("%v--%v\n", s1, s2)
fmt.Println("---------")
//切片的遍历
for i := 0; i < len(s1); i++ {
fmt.Println(s1[i])
}
fmt.Println("----------")
for i, v := range s1 {
fmt.Printf("%d--%d\n", i, v)
}
}
使用append函数为切片追加元素
Go语言的内建函数可以为append,可以动态添加元素,每个切片都会指向一个底层数组,这个数组能容纳一定数量的元素,当底层数组不能容纳新增的元素时,切片就会按照一定的扩容策略进行自动扩容,此时该切片指向的底层数组就会更换,扩容操作发生在append调用时。
append的扩容策略。
首先判断,如果新增的容量,大于旧的容量的2倍,最终容量就是新申请的容量。
否组判断,如果旧的切片的容量小于1024,那么新容量就是旧容量的2倍
否则判断,如果旧的切片的容量大于1042,那么新的容量就是旧的容量加上旧的容量的1/4
如果计算容量溢出,那么新的容量,就是新申请的容量
注意:元素类型不同的切片,扩容策略也是不同的
package main
import "fmt"
func main() {
s1 := []string{
"北京", "上海", "广州"}
//切片不可以使用索引的方式添加数据,会报(索引越界错误)
// s1[3] = "深圳"
//在切片中追加数据
//方式1,append的第一个参数是被添加的目标切片,第二个参数是添加的值
s1 = append(s1, "深圳")
fmt.Println("方式1")
fmt.Println(s1)
fmt.Printf("%d--%d\n", len(s1), cap(s1))
//方式2,添加多个值
s1 = append(s1, "围场", "承德")
fmt.Println("方式2")
fmt.Println(s1)
fmt.Printf("%d--%d\n", len(s1), cap(s1))
//方式3,在切片中,追加一个切片
var slice1 = []string{
"廊坊", "天津"}
s1 = append(s1, slice1...)
fmt.Println("方式2")
fmt.Println(s1)
fmt.Printf("%d--%d\n", len(s1), cap(s1))
// 切片的拷贝 copy函数
// copy函数,拷贝的切片会重新生成一个底层数组,和旧的底层数组不冲突
// 重新定义一个切片,类型,长度都要和以前切片一致
var ss1 = make([]string, len(s1), cap(s1))
ss2 := s1
copy(ss1, s1)
fmt.Printf("%v--%d--%d\n", ss1, len(ss1), cap(ss1))
ss2[0] = "成都"
fmt.Printf("%v--%v--%v\n", ss1, ss2, s1)
//在切片中,没有内置的删除函数,所以自己实现一段,实现删除功能的代码
a1 := [...]int{
1, 2, 3, 4, 5, 6, 7, 8, 9}
slice := a1[:]
//删除索引为2的数据
slice = append(slice[:2], slice[3:]...)
//因为在append函数中我们操作的是指向同一个数组的切片,所以我们就相当于在操作数组
//我们的目标切片是数组的1,2,我们后面追加的数据,就相当于是,依次修改了,底层数组中的代码
fmt.Printf("%v\n%v", slice, a1)
}