数组
数组
是一同一种数据类型元素的集合。在go语言中,数组从声明时就可以修改数组成员,但是数组大小不变化
数组是值类型而不是引用类型
因此数组支持"==","!="操作符,因为内存总是被初始化过的
数组的基本使用
package main
import "fmt"
func main() {
var a [3]bool //数组声明
//数组如果不初始化,默认元素是零,布尔值是false,字符串为空""
//初始化方式1
a = [3]bool{true, true, true}
fmt.Println(a)
//初始化方式2
a10 := [...]int{0, 1, 2, 3, 4, 5, 6, 7, 8} //也可以这样写 a10 := [9]int{0, 1, 2, 3, 4, 5, 6, 7, 8}
fmt.Println(a10)
//初始化方式3
a3 := [5]int{0: 1, 4: 2}
fmt.Println(a3) //[1 0 0 0 2]
//数组的遍历
citys := [...]string{"北京", "上海", "深圳"}
for i := 0; i < len(citys); i++ {
fmt.Println(citys[i]) //逐行输出 北京 上海 深圳
}
for i, v := range citys {
fmt.Println(i, v)
}
//多维数组
//[1,2][3,4][5,6]
var all [3][2]int
all = [3][2]int{
[2]int{1, 2},
[2]int{3, 4},
[2]int{5, 6},
}
fmt.Println(all)
fmt.Println("~~~~~~~~~~~~~~~~~~") //多维数组的遍历
for _, v1 := range all {
fmt.Println(v1)
for _, v2 := range v1 {
fmt.Println(v2)
}
}
}
切片
数组的长度是固定的,并且数组长度属于类型一部分,所以数组有很多局限性
切片是一个拥有相同类型元素的可变程度序列.他是基于数组做的一层封装,它非常灵活,支持自动扩容.切片是一个引用类型,它的内部结构包含,地址,长度,和容量.切片一半用于快速地操作一块数据集合
切片是引用数据类型,都指向了底层的数组
package main
import "fmt"
func main() {
var s1 []int //定义存放int类型元素的切片
var s2 []string //定义存放string类型的切片
fmt.Println(s1, s2) //[] []
//初始化
s1 = []int{1, 2, 3}
s1 = []int{1, 2, 3, 4}
s2 = []string{"qwe", "asd", "zxc", "123"}
fmt.Println(len(s1)) //长度3
//由数组拿到切片
a1 := [...]int{1, 2, 3, 4, 5, 6, 7, 8}
s3 := a1[:4] //基于一个元素切割,左包含右不包含
fmt.Println(s3) //[3 4]
//也有如下写法 c:=a[1:] 1到最后一位 c:=a[:4] 第0位到4 c:=a[:] 全部
//切片的容量是底层数组从第一个元素到最后的容量
}
本质
切片的本质就是一个框,框住了一块连续的内存.(go语言比较底层,所以只能保存相同的类型值,不像php,python)
切片属于引用类型,真正的数据都是保存在数组里的
用make函数创造切片
package main
import "fmt"
func main() {
//make函数创造切片,make是申请像操作系统开辟一块内存空间的
//当容量省略的时候默认容量是和长度一样的
s1 := make([]int, 5, 10)
s1 = nil
fmt.Println("值", s1, "长度", len(s1), "容量", cap(s1)) //值 [0 0 0 0 0] 长度 5 容量 10
}
概念
切片类型不能直接使用==操作符来进行比较
一个nill值的切片并没有底层数组,一个nil值的切片的长度和容量都是0
切片赋值的时候赋值的是内存地址
append
package main
import "fmt"
func main() {
s1 := []string{"北京", "上海", "深圳", "宁波"}
//调用append函数,必须用原来的切片变量接收返回值
s1 = append(s1, "广州", "大")
//append追加元素,原来的底层数组放不下的时候,就会把底层数组换一个
//新的数组
//首先判断,如果新申请的容量大于最终容量,也就是旧容量的俩倍,最终容量就是新申请的容量
//否则判断,如果切片长度小于1024,则最终容量是就容量的俩倍
//否则判断,如果切片长度大于等于1024,则最终容量从旧容量开始循环增加原来的四分之一,直到最终容量大于新申请的容量
//如果最终容量计算值一处,则最终容量就是新申请的容量
//需要注意的是,切片扩容还会根据切片元素类型的不同而做不同的处理,比如int和string的处理方式就是不一样的
fmt.Println(s1, cap(s1)) //[北京 上海 深圳 宁波 广州 大] 8
s1=append(s1,ss...)//表示拆开,类似js中的扩散
}
copy
package main
import "fmt"
func main() {
//copy函数就是将第一个元素的所有值拷到第二个,直接辅助是赋值的地址
a1 := []int{1, 2, 3}
a2 := a1
var a3 = make([]int, 3, 3) //要先声明空间
copy(a3, a1)
a1[2] = 6
fmt.Println(a1, a2, a3) //[1 2 6] [1 2 6] [1 2 3]
//删除将a1中索引为1的元素2删除
a1 = append(a1[:1], a1[2:]...)
fmt.Println(a1)
fmt.Println(cap(a1))
}
测试
package main
import "fmt"
func main() {
// x1 := [...]int{1, 3, 5}
// s1 := x1[:]
// fmt.Println(s1, len(s1), cap(s1)) //[1 3 5] 3 3
// s1 = append(s1[:1], 6, 2) //
// fmt.Println(s1, len(s1), cap(s1)) //[1 6] 2 3
// fmt.Println(x1) //[1 6 5]
a := []int{1, 2, 3}
b := a
a = append(a, 7)
fmt.Println(a, b) //[1 2 3 7] [1 2 3]
}
指针(和c语言类似)
package main
import "fmt"
func main() {
//取地址
n := 18
p := &n
fmt.Println(*p) //18
fmt.Println(p) //内存地址 0xc000064058
fmt.Printf("%T\n", p) //*int
fmt.Printf("%T\n", *p) //int
n = 20
fmt.Println(*p) //20
}
package main
import "fmt"
func main() {
//var a *int //定义一个int型的内存地址 定义的时候为空指针
//*a = 100//这样写会报错
//fmt.Println(*a)
//正确的写法为下
var a2 = new(int) //new函数申请一个内存地址
fmt.Println(a2)//0xc000064058
fmt.Println(*a2)//0
*a2 = 100
fmt.Println(*a2)
}
make也是用于分配额内存的,区别于slice,map以及chan的内存创建,而且它返回的类型就是这三个类型本身,而不是他们的指针类型,因为这三种类型就是引用类型,所以就没有必要返回他们的指针了。
new很少用,一般给基本数据类型申请内存,string、int
make是用啦igeislice,map,chan申请内存的,make函数返回的是对应这三个类型的本身
Map
map是一种无序的基于key-value的数据结构,go语言中的map是引用数据类型,必须初始化之后才能使用
package main
import "fmt"
func main() {
var m1 map[string]int //默认值为nil,还没有在内存中开辟空间
m1 = make(map[string]int, 10) //要估算好,map的容量,避免在程序运行期间再动态扩容
m1["理想"] = 18
m1["酷炫"] = 35
fmt.Println(m1) //map[理想:18 酷炫:35]
fmt.Println(m1["123"]) //0
value, ok := m1["qwq"]
println(ok, value) //false 0 直接复制是0
for k, v := range m1 { //遍历
println(k, v)
}
for k := range m1 { //只遍历key
println(k)
}
for _, v := range m1 {
println(v) //只遍历value
}
//删除
delete(m1, "理想")
fmt.Println(m1) //map[酷炫:35] 如果删除一个不存在的就没有操作
}
package main
import "fmt"
func main() {
//元素为切片类型的map
var s1 = make([]map[int]string, 10, 10)
s1[0] = make(map[int]string, 1)
s1[0][10] = "a"
fmt.Println(s1) //[map[10:a] map[] map[] map[] map[] map[] map[] map[] map[] map[]]
//值为切片类型的map
var m1 = make(map[string][]int, 10)
m1["北京"] = []int{10, 20, 30}
fmt.Println(m1) //map[北京:[10 20 30]]
}