Go语言基础之切片与map
切片
- 数组
- 一组数
- 数组是值传递的
- 创建数组 [size]int
- 数组的大小是不可变的
- 二维数组,数组套数组
- 冒泡排序
- 切片
- 切片本身是不存在数据的
- 底层是指向了一个数组
- 如果我们存放的数据大于了切片的容量,在底层就会扩容 copy > 1024 1.25倍
使用数组来创建切片
package main
import "fmt"
// 切片本身是不保存数据的,只是指向了底层数组。
func main() {
// 数组 [0,10) 数组的截取 [start,end]
// 数组
arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10} // 0xc000018230
// 通过数组来创建切片 [start,end)
/*
arr = 10个数
1, 0xc000000001
2, 0xc000000002
3, 0xc000000003
4, 0xc000000004
5, 0xc000000005
*/
s1 := arr[:5] // 1-5 // 0xc000018230 {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
s2 := arr[3:8] // 4-8 // 0xc000018248
s3 := arr[5:] // 6-10 // 0xc000018258
s4 := arr[:] // 0-10 // 0xc000018230
fmt.Println(s1)
fmt.Println(s2)
fmt.Println(s3)
fmt.Println(s4)
// 查看容量和长度
fmt.Printf("s1 len:%d, cap:%d\n", len(s1), cap(s1)) // s1 len:5, cap:10
fmt.Printf("s2 len:%d, cap:%d\n", len(s2), cap(s2)) // s2 len:5, cap:7
fmt.Printf("s3 len:%d, cap:%d\n", len(s3), cap(s3)) // s3 len:5, cap:5
fmt.Printf("s4 len:%d, cap:%d\n", len(s4), cap(s4)) // s4 len:10, cap:10
// 内存地址
fmt.Printf("%p\n", s1) // 指向了原数组
fmt.Printf("%p\n", s2) // 截断了后,指向了最新截断的元素的下标开始
fmt.Printf("%p\n", s3)
fmt.Printf("%p\n", &arr[5])
fmt.Printf("%p\n", s4) // 指向了原数组
fmt.Printf("%p\n", &arr)
// 修改数组的内容, 切片也随之发生了变化 (切:切片不保存数据-->底层的数组 )
arr[2] = 100
fmt.Println(arr) // [1 2 100 4 5 6 7 8 9 10]
fmt.Println(s1) // [1 2 100 4 5]
fmt.Println(s2) // [4 5 6 7 8]
fmt.Println(s3) // [6 7 8 9 10]
fmt.Println(s4) // [1 2 100 4 5 6 7 8 9 10]
fmt.Println("------------------------")
// 修改切片的内容,发现数组也随之发生了变化。(本质:修改的都是底层的数组)
s2[2] = 80
fmt.Println(arr) // [1 2 100 4 5 80 7 8 9 10]
fmt.Println(s1) // [1 2 100 4 5]
fmt.Println(s2) // [4 5 80 7 8]
fmt.Println(s3) // [80 7 8 9 10]
fmt.Println(s4) // [1 2 100 4 5 80 7 8 9 10]
fmt.Println("------------------------")
// 切片扩容
s1 = append(s1, 11, 12, 13, 14, 15, 16)
fmt.Println(arr) // [1 2 100 4 5 80 7 8 9 10]
// 如果在切片容量内加,会导致原来的数组数据发生修改。只有扩容之后,才会导致底层数组会产生拷贝。新的数组
fmt.Println(s1) // [1 2 100 4 5 11 12 13 14 15 16]
fmt.Println(s2) // [4 5 80 7 8]
fmt.Println(s3) // [80 7 8 9 10]
// 查看内存地址,已经不是同一个了
fmt.Printf("%p\n", s1) // 0xc0000d2000
fmt.Printf("%p\n", &arr) // 0xc0000ac0f0
}
切片:引用类型
package main
import "fmt"
func main() {
// 值类型,传递:copy
arr1 := [4]int{1, 2, 3, 4}
arr2 := arr1
fmt.Println(arr1, arr2)
arr1[0] = 100
fmt.Println(arr1, arr2)
// 切片:引用类型
s1 := []int{1, 2, 3, 4}
s2 := s1
fmt.Println(s1, s2)
s1[0] = 100
fmt.Println(s1, s2)
// 通过内存分析发现,s1,s2指向了同一个地址。
fmt.Printf("%p\n", s1)
fmt.Printf("%p\n", s2)
}
深拷贝、浅拷贝
深拷贝:拷贝是数据的本身
- 值类型的数据,默认都是深拷贝,array、int、float、string、bool、struct…
浅拷贝:拷贝是数据的地址,会导致多个变量指向同一块内存。
- 引用类型的数据: slice、map
- 因为切片是引用类的数据,直接拷贝的是这个地址
切片怎么实现深拷贝 copy
package main
import "fmt"
// 切片实现深拷贝
func main() {
// 将原来切片中的数据拷贝到新切片中
s1 := []int{1, 2, 3, 4}
s2 := make([]int, 0) // len:0 cap:0
for i := 0; i < len(s1); i++ {
s2 = append(s2, s1[i])
}
fmt.Println(s1)
fmt.Println(s2)
s1[0] = 100
fmt.Println(s1)
fmt.Println(s2)
// copy
s3 := []int{5, 6, 7}
fmt.Println(s2)
fmt.Println(s3)
// 将s3中的元素拷贝到s2中
//copy(s2, s3)
// 将s2中的元素拷贝到s3中
copy(s3, s2)
fmt.Println(s2)
fmt.Println(s3)
}
函数中参数传递问题
按照数据的存储特点来分:
- 值类型的数据:操作的是数据本身、int 、string、bool、float64、array…
- 引用类型的数据:操作的是数据的地址 slice、map、chan…
值传递
引用传递
package main
import "fmt"
func main() {
arr1 := [4]int{1, 2, 3, 4}
fmt.Println("arr1:", arr1)
update(arr1)
fmt.Println("end arr1:", arr1)
s1 := []int{1, 2, 3, 4}
fmt.Println("s1:", s1)
update2(s1)
fmt.Println("end s1:", s1)
}
// 函数补充:在使用函数的时候,一定要特别注意参数问题,如果是值类型的,很多传递是无效的。
// 一些值传递的类型的参数,如果我们想通过函数来进行修改对应的值,这个时候就需要使用指针
// 指针变量 -> 指向原来变量的地址
// 数组是值类型的
func update(arr [4]int) {
fmt.Println("--> arr:", arr)
arr[0] = 100
fmt.Println("--> end arr:", arr)
}
// 切片是引用类型的
func update2(s []int) {
fmt.Println("--> s:", s)
s[0] = 100
fmt.Println("--> end s:", s)
}
map
Map 是一种无序的键值对的集合。
- 无序 :map[key]
- 键值对:key - value /key - value key - value key - value
Map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值。
Map 是一种集合,所以我们可以像迭代数组和切片那样迭代它。
不过,Map 是无序的,我们无法决定它的返回顺序。
Map也是引用类型
map的定义
package main
import "fmt"
// map 集合,保存数据的一种结构
func main() {
// 创建一个map,也是一个变量,数据类型是 map
// map[key]value
var map1 map[int]string // 只是声明了但是没有初始化,不能使用 nil
if map1 == nil {
fmt.Println("map1==nil")
}
// 更多的时候使用的是make方法创建
var map2 = make(map[string]string) // 创建了map
fmt.Println(map1)
fmt.Println(map2)
// 在创建的时候,添加一些基础数据
// map[string]int nil
// map[string]int {key:value,key:value,......}
var map3 = map[string]int{"Go": 100, "Java": 10, "C": 60}
fmt.Println(map3)
// 关于map的类型,就如定义的一般 map[string]int
// 类型主要是传参要确定
fmt.Printf("%T\n", map3)
}
map的使用
- 创建并初始化map
- map[key] = value 。将vaule赋值给对应的map的key
- 判断key是否存在,value, ok = map[key]
- 删除map中的元素, delete(map,key)
- 新增 map[key] = value
- 修改 map[key] = value ,如果存在这个key就是修改。
- 查看map的大小, len(map)
package main
import "fmt"
// 内存中的一个简单的数据库。key - value 。 增删改查的。
// map的使用
// 定义 var m1 map[key]value make(map[key]value)
func main() {
// 创建map
var map1 map[int]string // nil,不能使用的,只是声明了,还没有初始化
// 给map1赋值
// 初始化map
map1 = make(map[int]string)
// 在map中如果你的key重复了,它就会覆盖这个key原来的值,一个key只能对应一个value
map1[100] = "学相伴"
map1[100] = "学相伴1111"
map1[200] = "狂神说"
// 获取数据 map[key]
fmt.Println(map1)
fmt.Println(map1[200])
fmt.Println(map1[1]) // 不存在,默认值 string ""
// map中,没有index下标,有时候我们取值就需要判断这个key是否存在了
// map中的判断,ok-idiom 是否存在的
// value = map[key] , 隐藏的返回值 ok-idiom , 可选参数
value, ok := map1[1]
//
if ok {
fmt.Println("map key 存在的,value:", value)
} else {
fmt.Println("map key 不存在的")
}
// 修改数据
map1[100] = "飞哥"
fmt.Println(map1)
// 如果数据存在,修改它,如果不存在,就会创建对应的 key-value
map1[1] = "xxxxxxxxxxxxxxx"
fmt.Println(map1)
// map中的数据删除问题 delete
delete(map1, 1)
fmt.Println(map1)
// map的大小
fmt.Println(len(map1))
}
map遍历
for k, v := range map1 , key-value,每次打印可能是无序的。
package main
import "fmt"
/*
遍历map
- key、value 无序的,遍历map,可能每次的结果排序都不一致。
- "aaa" "aaaaa"
- "bbb" "bbbbb"
- "ccc" "ccccc"
1、map是无序的,每次打印出来的map可能都不一样,它不能通过index获取,只能通过key来获取
2、map的长度是不固定的,是引用类型的
3、len可以用于map查看map中数据的数量,但是cap无法使用
4、map的key 可以是 布尔类型,整数,浮点数,字符串
*/
func main() {
var map1 = map[string]int{"Go": 100, "Java": 99, "C": 80, "Python": 60}
// 循环遍历,只能通过for range
// 返回 key 和 value
for k, v := range map1 {
fmt.Println(k, v)
}
}
map结合slice使用
package main
import "fmt"
// map 结合 slice 来使用
/*
需求:
1、创建map来存储人的信息,name,age,sex,addr
2、每个map保存一个的信息
3、将这些map存入到切片中
4、打印这些数据
*/
func main() {
user1 := make(map[string]string)
user1["name"] = "kuangshen"
user1["age"] = "27"
user1["sex"] = "男"
user1["addr"] = "重庆"
user2 := make(map[string]string)
user2["name"] = "feige"
user2["age"] = "30"
user2["sex"] = "男"
user2["addr"] = "长沙"
user3 := map[string]string{"name": "小蓝", "age": "18", "sex": "男", "addr": "火星"}
fmt.Println(user3)
// 3个数据有了,存放到切片中,供我们使用
userDatas := make([]map[string]string, 0, 3)
userDatas = append(userDatas, user1)
userDatas = append(userDatas, user2)
userDatas = append(userDatas, user3)
fmt.Println(userDatas)
// 0 map[string]string
for _, user := range userDatas {
//fmt.Println(i)
fmt.Println(user["addr"])
}
}
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果