容器

Array

1、定义、初始化数组(存储一组相同数据类型的数据结构、定长)

//定义
var arr_name [arr_len]Type
//Type:可以是任意基本类型,当类型为数组时,可实现多维数组

//初始化
var MyArray1 [7]string
MyArray1[0] = "hello"
MyArray1[1] = "monkey"

var MyArray2 = [7]int{1,2,3,4,5,6,7}
var MyArray3 = [5]float32{100.0,2.0,3.4,7.0,50.0}
var MyArray4 = [...]float32{1000.0,2.0,50.0}
//省略号表示数组长度是根据初始化值的个数计算的

2、遍历数组

//打印索引和值
for k,v := range MyArray{
     fmt.Println(k,v)
}

//仅打印值
for _,v := range MyArray{
   fmt.Println("%d",v)
}

5、比较两个数组是否相等

使用==!=比较两数组的前提:两数组类型相同(数组长度、数组元素类型)
只有两数组类型相同且两数组的所有元素都是相等的数组才能判等。

注:不能比较两个类型不同的数组,否则编译出错

4、向函数传递数组

void func1(param [10]int){
    //方法体
}
void func2(param []int){
     //方法体
}


Slice

Slice(切片)是对数组的抽象,即动态(变长)数组,长度不固定,可追加元素,追加时可能切片的容量增大,类似于Java的集合。是一个引用类型的容器,指向了一个底层数组

1、切片的生成

1:声明一个未指定大小的数组定义切片
var slice1 []int2make函数创建切片,len是数组的长度也是切片的初始长度
var slice2 []int = make([]int,len)//make函数创建切片
//或简写
slice2 := make([]int,len,[cap])
//cap为可选参数(预分配个数),len是实际为这个类型分配的元素个数
//栗子
a :=make([]int,2)
b :=make([]int,2,10)
fmt.Println(a,b) //[0 0] [0 0]
fmt.Println(len(a),len(b),cap(b)) //2 2 10

//从连续内存区域生成切片3:从数组生成切片
var a = [...]int{1,2,3}
var slice []int = a[1:2]
fmt.Println(a,a[1:2])//[1,2,3] [2]4:从切片生成切片
var a = [...]int{1,2,3}
var slice []int = a[0:]
var ss []int = slice[1:2]
//创建切片是之前切片的两倍容量
slice2 := make([]int,len(slice1),(cap(slice1))*2)
//获取切片最后一个元素
slice[len(slice)-1]

关于make()函数生成切片

  • 使用make()函数,生成的切片一定发生了内存分配的操作
  • 给定开始和结束位置的切片只是将新的切片结构指向已经分配好的内存区域,设定开始与结束位置,不会发生内存分配操作

重要的栗子:切片声明过程和内存的关系

//声明字符串切片
var str []string

//声明整型切片
var num []int

//声明空切片
var numEmpty = []int{}

//输出3个切片
fmt.Println(str,num,numEmpty)//[] [] []

//输出3个切片的大小
fmt.Println(len(str),len(num),len(numEmpty))//0 0 0

//判断切片是否为空
fmt.Println(str == nil)//true
fmt.Println(num == nil)//true
fmt.Println(numEmpty == nil)//false
  • 声明但未使用的切片默认是nil
  • numEmpty是声明且已经分配了内存空间,只是没有填充值进去,故不是nil
  • 切片是动态结构的,只能与nil判定相等,不能切片之间相互判等

2、方法

s := make([]int,3,8)//len=3,cap=8,[0,0,0]
s[0] = 1
s[1] = 2
s[2] = 3
//s[3] = 4 //报错
//fmt.Println(s[3])//panic:runtime error:index out of range
//在初始长度的基础上添加元素使用append函数

①添加元素append() 注:append()返回的是新切片
添加元素时,若空间不足以容纳足够多的元素,切片就会进行扩容,新切片的长度将会发生改变。切片在扩容时,容量的扩展规律是按容量的2倍数进行扩充

往尾部和首部添加

//尾部添加(元素、切片)
var slice1 []int
slice1 = append(slice1,3)//一次添加1个元素
slice1 = append(slice1,1,2,3)//一次添加多个元素
//
group := []string{"hello","monkey"}
slice2 = append(slice2,group...)//表示将group整个添加到slice2后面

//头部添加(元素、切片)
var num = []int{1,2,3}
num = append([]int{0},num...)
num = append([]int{-3,-2,-1},a...)

但是切片开头添加元素一般会导致内存的重新分配,导致已有的元素被复制一次,故从切片的开头添加元素的性能要比从尾部追加元素的性能差很多

实现任意位置插入元素

var a []int
//在第i个位置插入x
a = append(a[:i],append([]int{x},a[i:]...)...)
//在第i个位置插入切片
a = append(a[:i],append([]int{1,2,3},a[i:]...)...)

②切片赋值copy()

copy(slice1,slice2)//将slice2的内容拷贝到slice1

③删除元素
Go语言没有提供直接对切片删除元素的接口,只能通过append实现

删除下标为2的元素
seq := []string{"monkey","hello","world","hi"}
index := 2
seq = append(seq[:index],seq[index+1]...)

对比C语言指针,关于切片内存的理解

  • 指针可以做运算,但可能出现内存操作越界
  • 切片在指针的基础上增加了大小,约束了切片对应的内存区域,切片使用中不能实现对切片内部的地址和大小进行手动调整,故切片比指针更安全强大

总结关于关于切片的内存
1、每一个切片引用了一个底层数组
2、切片本身不存储任何数据,都是相应的底层数组存储,故修改切片也就是修改这个数组中的数据
3、向切片中添加数据时,若没有超过容量cap,直接添加,若超过容量,自动扩容(成倍增长)
4、切片一旦扩容,就重新指向一个新的底层数组



Map

1、声明定义初始化

var map_name map[key_type]value_type
//
var MyMap map[string]string
//key_type和value_type之间允许有空格
var MyMap map[string] string
//使用make,cap为map初始容量
make(map[key_type]value_type,cap)
  • map是引用类型
  • map声明时默认值是nil
  • 声明时不需要知道map长度,因为它是可以动态增长的
  • 未初始化进行取值,返回的为对应类型的零值
  • 通过下标的方式访问map的元素会得到两个值,第二个值是布尔值,报告该元素是否存在.

通过key作为下标访问只声明但未初始化的map返回值:value和布尔值

bool的零值是false
var m1 map[int]bool
num1,bo1 := m1[1]
fmt.Println(num1,bo1) //false false

int的零值是0
var m2 map[int]int
num2,bo2 := m2[1]
fmt.Println(num2,bo2) //0 false

2、初始化

  • 在声明map之后必须初始化,若向未初始化的map赋值会引起panic:assign to entry in nil map
1:先声明后初始化
var m1 map[string]int
m1 = make(map[string]int)
//或
m1 = map[string]int{}2:声明同时初始化
m :=make(map[string]int)
m :=map[string]int{1:1}
//或
m := make(map[string]int,100)//初始容量100

map的修改、赋值、引用

package main
import "fmt"
func main(){
	var MyMap1 map[string]int
	var MyMap2 map[string]int
	//var MyMap3 map[string]int
	MyMap1 = map[string]int{"one":1,"two":2}
	MyMap3 := make(map[string]float32)
	MyMap2 = MyMap1
	MyMap3["key1"] = 3.7
	MyMap3["key2"] = 4.5
	MyMap2["two"] = 3
	fmt.Println("MyMap1:",MyMap1)
	fmt.Println("MyMap2:",MyMap2)
	fmt.Println("MyMap3:",MyMap3)
}

在这里插入图片描述
①MyMap3的创建方式MyMap3 := make(map[string]float)等价于MyMap3 := map[string]float{}
②MyMap2是MyMap1的引用,如结果,对MyMap2的修改也影响了MyMap1的值
③注意:创建map可以使用make()函数但不能使用new()来构造map。若错误使用new()分配了一个引用对象会获得一个空引用的指针,相当于声明了一个未初始化的变量并且取了它的地址。如

MyMap4 := new(map[string]float32)
MyMap4["key1"] = 4.5
//此时编译器报错

将切片作为map的值
应用:处理unix机器上所有进程,以父进程(pid整型)作为key,所有子进程作为value
实现一个key对应多个value,使用切片

map1 := make(map[int][]int)
map2 := make(map[int]*[]int)

3、方法
添加&删除&更新&查询

//添加
Mymap["id"] = "2018110"
//删除
delete(Mymap,"id")
//更新
Mymap["id"] = "2019110"
//查询
i := Mymap["id"]
i,ok := Mymap["id"]
_,ok := Mymap["id"]

关于清空map中所有元素:Go语言没有提供任何方法和函数,清空的办法就是重新make一个新的map。Go语言的并行垃圾回收效率比写一个清空函数要高效很多。

4、遍历

  • map本身是无序的,不会按照传入的顺序顺序输出
  • Map的元素不是变量,并不能获取其地址,因为map的增长可能会导致已有元素被重新散列到新的存储位置,可能使得获取的地址无效

原始(无序、key-value)遍历

for k,v := range MyMap{
     fmt.Println(k,v)
}

原始(无序、只有value)遍历

for _,v  := range MyMap{
     fmt.Println(v)
}

有序遍历

import "sort"
var keys []string
//把key单独取出来,放在数组里面
//append()返回的是新切片
for k,_ := range Mymap{
   keys = append(keys,k)
}
//对数组进行排序
sort.Strings(keys)
//处理后的数组keys为有序
for _,k := range keys{
     fmt.Println(k,Mymap[k])
}

判断key是否在map中

if _,ok := map[key];ok{
   //执行语句
}


List

list(列表)没有具体元素类型的限制,即列表里元素可以是任意类型
1、初始化列表

1:通过container/list包的New()函数初始化list
var_name := list.New()2:通过var关键字声明初始化list
var var_name list.List

2、方法

i := list.New()//创建一个列表实例

//将first字符串插入到列表的尾部,插入后只有一个元素
i.PushBack("first")
//此时列表中已经存在first字符串

//将数字32插入列表的头部,即插入后32这个元素将被放在first的前面
i.PushFront(32)

3、遍历
Font()函数获取头元素

i := list.New()
i.PushBack("first")
i.PushBack(32)

for k:=i.Front();i!=nil;i=i.Next(){
    fmt.Println(k.Value)
}
/*
32
first
*/
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值