golang复杂数据结构
数组
**数组是一个由固定长度的特定类型元素组成的序列,一个数组可以由零个或多个元素组成。**因为数组的长度是固定的,因此在Go语言中很少直接使用数组。
数组的每个元素可以通过索引下标来访问,索引下标的范围是从0开始到数组长度减1的位置。内置的len函数将返回数组中元素的个数。
var a [3]int // 长度为3的数组
fmt.Println(a[0]) // 打印第一个数据
fmt.Println(a[len(a)-1]) // 打印最后一个数据
for i, v := range a {
fmt.Printf("%d %d\n", i, v) // 循环数组 i为索引 v为数据
}
默认情况下,数组的每个元素都被初始化为元素类型对应的零值
数组的初始化:
var a [3]int = [3]int{1, 2, 3}
b := [...]int{1, 2, 3}
a = [4]int{1, 2, 3, 4} // panic 数据初始化就是定长了 长度不能变化
切片
Slice(切片)代表变长的序列,序列中每个元素都有相同的类型。一个slice类型一般写作[]T,其中T代表slice中元素的类型;slice的语法和数组很像,只是没有固定长度而已。
一个slice由三个部分构成:指针、长度和容量。指针指向第一个slice元素对应的底层数组元素的地址,要注意的是slice的第一个元素并不一定就是数组的第一个元素。长度对应slice中元素的数目;长度不能超过容量,容量一般是从slice的开始位置到底层数据的结尾位置。内置的len和cap函数分别返回slice的长度和容量。
多个slice之间可以共享底层的数据,并且引用的数组部分区间可能重叠。
使用make()函数构造切片
make([]T, size, cap) // T:切片类型 size 切片数量 cap 切片容量
append()方法为切片添加元素
sli := make([]int,0,10)
sli = append(sli,1) // 添加一个 1
arr := [4]int{6,7,8,9}
sli = append(sle,arr...) // 把arr打散并全部添加 添加多个
fmt.Println(sli) // [1 6 7 8 9]
从切片中删除元素
// 从切片中删除元素
a := []int{30, 31, 32, 33, 34, 35, 36, 37}
// 要删除索引为2的元素
a = append(a[:2], a[3:]...)
fmt.Println(a) //[30 31 33 34 35 36 37]
切片的扩容策略
func growslice(et *_type, old slice, cap int) slice {
newcap := old.cap
doublecap := newcap + newcap
if cap > doublecap {
newcap = cap
} else {
if old.len < 1024 {
newcap = doublecap
} else {
for 0 < newcap && newcap < cap {
newcap += newcap / 4
}
if newcap <= 0 {
newcap = cap
}
}
}
在分配内存空间之前需要先确定新的切片容量,Go 语言根据切片的当前容量选择不同的策略进行扩容:
- 如果期望容量大于当前容量的两倍就会使用期望容量;
- 如果当前切片容量小于 1024 就会将容量翻倍;
- 如果当前切片容量大于 1024 就会每次增加 25% 的容量,直到新容量大于期望容量;
MAP
哈希表是一种巧妙并且实用的数据结构。它是一个无序的key/value对的集合,其中所有的key都是不同的,然后通过给定的key可以在常数时间复杂度内检索、更新或删除对应的value。在Go语言中,一个map就是一个哈希表的引用,map类型可以写为map[K]V,其中K和V分别对应key和value。
- 初始化:
m := make(map[string]int)
- 赋值初始化
m := map[string]int{
"zhy": 18,
"who": 30,
}
// 直接赋值相当于
ages := make(map[string]int)
ages["zhy"] = 18
ages["who"] = 30
**Map的迭代顺序是不确定的,并且不同的哈希函数实现可能导致不同的遍历顺序。**遍历的顺序是随机的,每一次遍历的顺序都不相同。
如果要有序:
// 用sort进项排序
var names []string
for name := range ages {
names = append(names, name)
}
sort.Strings(names)
for _, name := range names {
fmt.Printf("%s\t%d\n", name, ages[name])
}
结构体
结构体是一种聚合的数据类型,是由零个或多个任意类型的值聚合成的实体。每个值称为结构体的成员。
type people struct {
name string
age uint8
hobby []string
address string
sex uint8
}
var zhy people
结构体赋值
h := []string{"唱","跳","RAP","篮球"}
zhy := people{"zhaohaiyu",18,h,"地球",1}
或者
var zhy people
zhy.name = "zhaohaiyu"
zhy.age = 18
zhy.hobby = h
zhy.address = "地球"
zhy.sex = 1
结构体比较
如果结构体的全部成员都是可以比较的,那么结构体也是可以比较的,那样的话两个结构体将可以使用或!=运算符进行比较。相等比较运算符将比较两个结构体的每个成员,因此下面两个比较的表达式是等价的:
type Point struct{ X, Y int }
p := Point{1, 2}
q := Point{2, 1}
fmt.Println(p.X == q.X && p.Y == q.Y) // "false"
fmt.Println(p == q) // "false"
结构体的继承
在java,python,cpp等语言中都有类的继承的概念,go语言中没有类.用结构体的嵌套实现继承.
type animal struct {
name string
age int
}
type people struct {
address string
animal animal
}
var zhy = people{
address: "地球",
animal: animal{
name: "zhaohaiyu",
age: 18,
},
}
fmt.Println(zhy.animal) // {zhaohaiyu 18}
fmt.Println(zhy.animal.name) // zhaohaiyu
fmt.Println(zhy.animal.age) // 18
fmt.Println(zhy.address) //地球
JSON
JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式。它基于ECMAScript(欧洲计算机协会制定的js规范)的一个子集,采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率。
Go语言对于这些标准格式的编码和解码都有良好的支持,由标准库中的encoding/json包提供支持
JSON是对JavaScript中各种类型的值——字符串、数字、布尔值和对象——Unicode本文编码。它可以用有效可读的方式表示第三章的基础数据类型和本章的数组、slice、结构体和map等聚合数据类型。
- 各类型的json数据
boolean true
number -273.15
string "hello world!!!!"
array ["i", "you", "her"]
object {"year": 2020,
"event":"huawei","American virus","Trump is crazy"}
- go语言结构体成员Tag来指定对应的JSON名字。同样,在解码的时候也需要做同样的处理
type People struct {
Name string `json:"name"`
Age int `json:"age"`
PhoneNumber string `json:"phone_number"`
}
- 要将结构体的数据发给游览器前端或者安卓,IOS,APP等进行展示,因为go语言首字母小写只能本包用,在外部包要首字母大写,包括结构体和结构体成员.而且go语言崇尚驼峰体命名,而很多语言崇尚下划线命名.所有我们要用tag把json数据的成员变成首字母小写以及下划线命名.