数组
数组:具有相同类型的⼀一组⻓长度固定 的数据序列列
声明语法 :var 变量量名 [数组⻓长度] 数据类型
import "fmt"
func main() {
fmt.Println("数组测试。。。")
//方式1:定义定长数组并完成初始化
var arr0 = [3]float64 {2.1, 3.2, 4.6}
fmt.Println(arr0)
fmt.Println("-----------")
//方式2:定义数组,后完成初始化
var arr1 [3]int
arr1[0], arr1[1], arr1[2] = 1, 2, 3
fmt.Println(arr1)
fmt.Println("-----------")
//方式3:初始化定义数组,并自动推导长度
var arr2 = [...]byte{1,2,3}
fmt.Println(arr2)
//数组地址,可观察到,数组中地址连续
fmt.Println(&arr2[0]) //0xc0000160e0
fmt.Println(&arr2[1]) //0xc0000160e1
fmt.Println(&arr2[2]) //0xc0000160e2
}
切片
可理解为变长数组。
切⽚片本身没有任何数据,只是对现有数组的引⽤。
slice三要素:
- 指针:指向数组中slice指定的开始位置
- 长度:即slice的长度
- 最大长度:slice开始位置到数组最后位置的长度
声明语法:var identifier []type
切片声明
import "fmt"
func main(){
//方式1:自动推导类型
s1 := []int{1,2,3} //定义切片
fmt.Println(s1)
//方式2: 定义并完成初始化
var s2 = []int{1,2,3}
fmt.Println(s2)
//方式3,使用make函数
//make([]T, length, capacity) 类型、长度、容量。其中容量capacity为可选参数。
s3 := make([]int,3)
s3[0] = 1
s3[1] = 2
fmt.Println(s3) // [1 2 0] []int类型未初始化的元素为0
s4 := make([]string,3)
s4[0] = "a"
s4[1] = "b"
fmt.Println(s4) // [a b ] []string类型 未初始化的元素为空
}
切片验证
验证结果:
- 切片本身为指针,用来指向数组
- 切片间可共享数组(相同容量间)
- 切片扩容时,会重新开辟数组空间,并完成值copy
import "fmt"
func main(){
a1 := [3]int{1,2,3}
fmt.Println("数组内容:",a1)
fmt.Println("首元素地址:",&a1[0]) //0xc00000c340
fmt.Printf("a1地址:%p\n",&a1) //0xc00000c340 说明输出为数组起始地址,即第一个元素地址
fmt.Println("-------------")
s1 := a1[0:1]
fmt.Println(&s1[0]) //0xc00000c340 s1[0]与a[0]地址相同,说明切片本身是一个指针。指向数组
fmt.Println("切片容量:",cap(s1))
fmt.Println("切片内容:",s1)
fmt.Println("-------------")
s2 := append(s1,4)
fmt.Println(&s2[0]) //0xc00000c340 s2[0]与s1[0]相同,说明切片间共享数组
fmt.Println("切片容量:",cap(s2))
fmt.Println("切片内容:",s2)
fmt.Println("-------------")
s3 := append(s2,5,6,7)
fmt.Println(&s3[0]) //0xc00000a3f0 s3[0]与s2[0]不同,切片扩容后,重新开辟空间
fmt.Println("切片容量:",cap(s3))
fmt.Println("切片内容:",s3)
/*
通过切片s2修改s2[0], 发现s1[0]、a1[0]、s2[0] 均发生改变。进一步说明扩容前数组共享
而s3[0]未被修改,说明扩容后的切片会重新开辟数组空间,并copy数组值,
*/
s2[0] = 10
fmt.Println(a1[0]) //10
fmt.Println(s1[0]) //10
fmt.Println(s2[0]) //10
fmt.Println(s3[0]) //1
}
指针
指针:存储某个变量起始内存地址 的变量
声明指针
声明格式:var 指针变量名 *指针类型
- 操作符 “&” 取变量地址, “*” 通过指针访问目标对象
- 指针不能运算
- 当一个指针被定义后没有分配到任何变量量时,它的值为 nil。 nil 指针也称为空指针
import "fmt"
func main(){
a := 10
fmt.Printf("a的地址为%p\n",&a) //0xc0000160b0
var p1 *int
if p1 == nil { //判断p1是否为nil。
fmt.Println("p1为nil 。。。")
p1 = &a
}
fmt.Println(p1) // 0xc0000160b0 输出为a的内存地址
fmt.Printf("p的地址为%p\n",&p1) //0xc000006030 自身所占内存地址
fmt.Println(*p1) //10 内存地址中所指向的值
*p1 = 20 //使用指针修改所指向变量的值
fmt.Println("a的值为:",a) //20
}
指针数组
指针数组:元素为指针类型的数组
eg: var p [3]*string
import "fmt"
func main(){
fmt.Println("指针数组测试。。。")
//定义三个int变量
a := 10
b := 20
c := 30
fmt.Println(&a) //0xc0000160c0
fmt.Println(&b) //0xc0000160c8
fmt.Println(&c) //0xc0000160d0
//定义指针类型的数组
var p1 [3]*int
//将变量地址存入数组中
p1[0] = &a
p1[1] = &b
p1[2] = &c
//输出指针数组
fmt.Println(p1) //[0xc0000160c0 0xc0000160c8 0xc0000160d0]
}
数组指针
数组指针:指向数组类型的指针
import "fmt"
func main(){
fmt.Println("数组指针测试。。。")
a, b, c := 10, 20, 30
//定义数组
var arr [3]int
arr[0] = a
arr[1] = b
arr[2] = c
fmt.Println("数组:",&arr) //数组:&[10 20 30] 数组地址为其中元素的地址范围,数组本身没有确定地址。
//定义数组指针
var p1 *[3]int
//指针指向数组
p1 = &arr
fmt.Println("p1指针指向:",p1) //输出指向 &[10 20 30]
fmt.Println("p1指针指向:",*p1) //输出指向内容 [10 20 30]
//使用指针修改数组值
p1[0] = 100
fmt.Println("数组:",arr) // [100 20 30] 数组中值被修改
fmt.Println("a的值:",a) //a的值没有变化,因为,数组中存储的是a变量的值拷贝。而不是a本身
}
map
map:是Go中的内置类型。是一种无序的键值对集合。
声明map
声明语法:
1)var 变量量名 map[key类型]value类型
2)变量量名 := make(map[key类型]value类型)
import "fmt"
func main(){
//方式1:使用var定义
var stu = map[int]string{}
stu[01] = "zhangsan"
stu[02] = "lisi"
stu[03] = "wangwu"
fmt.Println(stu)
//方式2:使用make函数
var stu2 = make(map[int]string)
stu2[01] = "二狗"
stu2[02] = "三猪"
stu2[03] = "四鸭"
fmt.Println(stu2)
//方式3:自动推导类型
stu3 := map[int]string{
01:"哈哈哈",
02:"嘿嘿嘿",
03:"呵呵呵",
}
fmt.Println(stu3)
}
使用细节:
- map是无序的,每次打印出来的map都会不⼀样,它不能通过index获取,而必须通过key获取。
- map的长度是不固定的,可扩展。内置len(),但无法使用cap()
- 同⼀个map中key必须保证唯一。
- key的数据类型必须是可参与比较运算的 类型,也就是支持==或!=操作的类型。如布尔型、整数型、浮点型、字符串串 型、数组。对于切片、函数等引用类型则不能作为键的类型。
- 和slice⼀一样,map也是⼀种引用类型
操作map
查看元素是否存在:value, ok := map[key]
删除:delete(map, key)
清空map
- Go语言没有为map提供任何清空所有元素的函数;
- 清空map的唯一办法是重新make一个新的map;
- 不用担心垃圾回收的效率,Go语⾔言的垃圾回收比写一个清空函数更高效
//操作map demo
import "fmt"
func main(){
//定义map
stu3 := map[int]string{
01:"哈哈哈",
02:"嘿嘿嘿",
03:"呵呵呵",
04:"哼哼哼",
}
fmt.Println(stu3)
//判断key=04的键值对是否存在,存在则删除
v , ok := stu3[04]
if ok {
println("将要删除:",v)
delete(stu3,04) //删除
}
//遍历
for k, v := range stu3{
fmt.Println(k,v)
}
}