数组用来保存一组相同类型的数据,go语言数组也分一维数组和多维数组。
直接上代码看一下一维数组特性
package main
import "fmt"
func main(){
//1.定义数组 var 数组名称 [元素个数]数据类型
var arr1 [2]int //[0 0]定义就有为0的默认值
var arr2 [3]bool //[false false false]
//2.多种初始化方式
//定义时完全初始化
var arr3 [3]int = [3]int{1,3,5} //[1 3 5]
//定义时部分初始化
var arr4 [3]int = [3]int{8,9} //[8 9 0]
//定义时指定元素初始化
var arr5 [3]int = [3]int{0:8,2:9} //[8 0 9]
//先定义再逐个初始化,访问数组通过 数组名称[索引] 的方式
var arr6 [3]string
arr6[0] = "ok"
arr6[1] = "hello"
arr6[2] = "world"
//先定义再一次性初始化(与C语言数组不同)
arr1 = [2]{1,2} //[1 2]
arr2 = [3]{true,true,false} //[true true true]
//3.定义元素同时初始化,元素的个数可以省略,使用 ... 代替
var arr7 = [...]int{1,3,5} //[1 3 5]
var arr8 = [...]int{6:5} //[0 0 0 0 0 0 5]
//4.两种遍历数组的方式,for循环遍历,for...range循环遍历
arr := [...]int{1,3,5}
for i:=0; i<len(arr); i++{
fmt.Println(i, arr[i])
}
for i,v := range arr{
fmt.Println(i,v)
}
}
数组的注意点
go语言中数组长度是数据类型的一部分,长度不同类型不同,不能比较。
go语言数组类型相同,在比较时会按照“对应索引的元素”进行比较,所有元素都相同返回true,否则返回false
go语言的数组是值类型,赋值和传参会复制整个数组
package main
import "fmt"
func main(){
var arr1 [2]int
var arr2 [3]int
var arr3 [3]int
var arr4 [3]int
fmt.Println(arr2 == arr3) // true
// go语言中数组长度是数据类型的一部分,长度不同类型不同,不能比较。
//fmt.Println(arr1 == arr2) 编译报错
//go语言数组类型相同,在比较时会按照“对应索引的元素”进行比较,所有元素都相同返回true,否则返回false
arr2 = [3]int{1,2,3}
arr3 = [3]int{1,2,3}
arr4 = [3]int{3,2,1}
fmt.Println(arr2 == arr3) // true
fmt.Println(arr2 == arr4) // false
//go语言的数组是值类型,赋值和传参会复制整个数组
arr4 = arr2
arr2[0]=3
fmt.Println(arr2) //[3 2 3]
fmt.Println(arr4) //[1 2 3]
}
二维数组
package main
import "fmt"
func main(){
//创建一个两行三列数组
arr := [2][3]int{
{1,2,3},
{4,5,6}, //注意:数组换行需要逗号结尾
}
fmt.Println(arr) //[[1 2 3][4 5 6]]
//创建多维数组只允许第一维使用 ...
arr1 := [...][3]int{
{1,2,3},
{4,5,6}
}
fmt.Println(arr1)
}
切片可以简单理解为长度可以变化的数组,但是go语言的切片本质上是结构体,用来解决数组在应用中长度不可变的问题
切片源码
type slice struct{
array unsafe.Pointer //指向底层数组指针
len int //切片长度(已经保存了多少个元素)
cap int //切片容量(可以保存多少个元素)
}
切片的创建方式
package main
import "fmt"
func main(){
//1.通过数组创建切片----------------------(切片的底层会指向数组,修改切片会修改对应位数组的值)
var arr = [5]int{1,3,5,7,9}
var sce = arr[1:3] //从下标1开始,一直取到3下标的前一个索引(左闭右开)
fmt.Println(sce) //[3 5]
fmt.Println(len(sce)) //切片的长度2 = 3 - 1 结束位置减开始位置
fmt.Println(cap(sce)) //切片的容量4 = 5 - 1 数组长度减开始位置
fmt.Printf("%p\n",&arr)
fmt.Printf("%p\n",&arr[0]) //数组地址 是 数组首元素地址
fmt.Printf("%p\n",&arr[1])
fmt.Printf("%p\n",sce) //切片地址 是数组中指定的 开始元素的地址 (&arr[1])
//指定骑士位置的四种方式
var sce1 = arr[1:2] //指定开始和结束
var sce2 = arr[:2] //只指定结束
var sce3 = arr[2:] //只指定开始
var sce4 = arr[:] //都不指定
//2.通过make函数创建q切片 make(类型,长度,容量)
//内部会先创建一个数组,然后让切片指向数组
//如果没有指定容量,那么容量和长度一样
var sce5 = make([]int,3,5)
fmt.Println(sce5) //[0 0 0]
fmt.Println(len(sce5)) //3
fmt.Println(cap(sce5)) //5
/*实现
var arr [5]int
var sce = arr[0:3]
*/
//3.通过go提供的语法糖快速创建
//和创建数组相同,但是不能指定长度
//创建时,切片的容量和长度相等
var sce6 = []int{1,3,5}
fmt.Println(sce6)
fmt.Println(len(sce6)) //3
fmt.Println(cap(sce6)) //3
}
切片的使用
package main
import "fmt"
func main(){
var sce = []int{1,3,5}
//1.同数组一样,使用 切片名称[索引] 的方式操作切片
sce[1] = 666
//2.不能越界
sce[5] = 1 //编译报错
//3.使用append方法对切片扩容----------------------------(返回新切片不会修改源底层指向数组)
//append(切片,元素)会在切片末尾添加一个元素,返回追加数据之后的切片
//追加后没有查出切片容量,返回原切片,超出容量返回新切片
//append 每次扩容会按照(原有切片容量*2)的方式扩容
fmt.Println(sce) //[1,666,5]
fmt.Println(len(sce)) //3
fmt.Println(cap(sce)) //3
fmt.Printf("%p\n",sce) //一个地址
sce = append(sce , 666)
fmt.Println(sce) //[1,666,5,666]
fmt.Println(len(sce)) //4
fmt.Println(cap(sce)) //6
fmt.Printf("%p\n",sce) //一个新地址
//4.使用copy用于两个切片之间数据拷贝 copy(目标切片,切片源)
var sce1 = []int{1,2,3}
var sce2 = make([]int,5)
var sce3 = make([]int,2)
//复制sce1的切片数据到sce2,这时他们的内存指向地址不同
copy(sce2,sce1) //sce2 [1,2,3,0,0]
//拷贝数据以小容量为准
copy(sce3,sce1) //sce3 [1,2]
//切片是引用传递 底层会指向同一个数组,再次修改sce2,sce1也会变
sce2 = sce1
}
切片的注意点
package main
import "fmt"
func main(){
//1.可以通过切片中再次生成新的切片,两个切片底层指向同一数组,修改一个会影响另一个
arr := [5]int{1,3,5,7,9}
sce1 := arr[0:4]
sce2 := sce1[0:3]
fmt.Println(sce1) //[1 3 5 7]
fmt.Println(sce2) //[1 3 5]
sce2[1] = 666
fmt.Println(sce1) //[1 666 5 7]
fmt.Println(sce2) //[1 666 5]
fmt.Println(arr) //[1,666,5,7,9] 会修改指向的数组
//2.切片只支持判断是否为nil,不支持==、!= 判断
//fmt.Println(sce1 == sce2)//编译报错
fmt.Println(sce1 != nil)//true
fmt.Println(sce2 == nil)//false
//3.只声明当没有被创建的切片是不能使用的
var arr [3]int //数组声明后直接可使用
var sce []int //切片生命后不能直接使用 只有通过make或者放糖创建后才会开辟空间使用
var sce[0] = 2 //编译报错
//4.字符串的底层是[]byte数组,所以字符也支持切片操作
str := "abcdefg"
sce1 := str[3:]
fmt.Println(sce1)
sce2 := make([]byte,10)
//第二个参数只能是slice或者数组
//将字符串拷贝到切片中
copy(sce2,str)
fmt.Println(sce2) //[97 98 99 100 101 102 103 0 0 0]
}