Go语言学习-部分(6) 切片 map

8 篇文章 0 订阅

Go语言学习-部分(6) 切片 map

切片(Slice):
引言:

  • 之前学习的数组限制性很多,首先长度也是数组类型的一部分,这样使得定义出来的数组只能接收固定长度的数组
  • 另外如果定义了一个数组var s = [3]{1,2,3}这样数组s已经有三个值了,没有办法在向里面添加值.
切片:

切片(Slice)是一个拥有相同类型元素的可变长度的序列。它是基于数组类型做的一层封装。它非常灵活,支持自动扩容
(简单的,我们就可以把它理解成数组切割一部分变成的,方便记忆)

切片是一个引用类型,它的内部结构包含地址、长度和容量。切片一般用于快速地操作一块数据集合。
声明切片类型的基本语法如下:

var a = []T

其中

  • name:表示变量名
  • T:表示切片中的元素类型
    :用法基本和数组类似,但是[]里面没有东西.
    初始化:与数组类似
var a = []int{1,2,3}
var b = []string{"大大","小小","钱钱"}

切片的长度和容量
切片拥有自己的长度和容量,我们可以通过使用内置的len()函数求长度,使用内置的cap()函数求切片的容量。
由数组得到切片:

var a = [...]int {1,2,3,4,5,6}//定义一个数组
s := a[0:4]//通过数组切割,左包含右不包含1,2,3,4
fmt.Println(s)

还可以这样截:
a[1:]//从前面索引截到最后
a[:4]//从后面这个索引截到前面
a[:]//截取所有

切片再切片

  • 切片的长度就是元素的个数
  • 而切片的容量是他底层数组的容量,准确的说是从切片地第一个索引到底层数组的最后一个索引.

在这里插入图片描述

在这里插入图片描述

make函数创建切片

s1 := make([]int,5,10) //make(类型,长度,容量(不写默认和长度一致))
//此时内容全是0,没有初始化(赋值)默认都是0

切片的本质:

  • 切片就是一个框,框住了一块连续的内存
  • 切片属于引用类型,真正的数据都是保存在底层数组里

如果切片是nil的那么它长度和容量一定是0;
但如果她的长度和容量是0,切片并不一定是nil;

var s1 []int         //len(s1)=0;cap(s1)=0;s1==nil
s2 := []int{}        //len(s2)=0;cap(s2)=0;s2!=nil
s3 := make([]int, 0) //len(s3)=0;cap(s3)=0;s3!=nil

判断切片是否为空的需要用len()判断,而不能s==nil
切片的赋值拷贝:
下面的代码中演示了拷贝前后两个变量共享底层数组,对一个切片的修改会影响另一个切片的内容,这点需要特别注意。

func main() {
	s1 := make([]int, 3) //[0 0 0]
	s2 := s1             //将s1直接赋值给s2,s1和s2共用一个底层数组
	s2[0] = 100
	fmt.Println(s1) //[100 0 0]
	fmt.Println(s2) //[100 0 0]
}

切片遍历

  • 索引的方式
  • for range

append()方法为切片添加元素:
Go语言的内建函数append()可以为切片动态添加元素。 可以一次添加一个元素,可以添加多个元素,也可以添加另一个切片中的元素(后面加)。

func main(){
	var s []int
	s = append(s, 1)        // [1]
	s = append(s, 2, 3, 4)  // [1 2 3 4]
	s2 := []int{5, 6, 7}  
	s = append(s, s2...)    // [1 2 3 4 5 6 7]
}

举例错误写法:

var s = []string{"大","小","多"}
append(s,"少")//错误写法,会导致切片索引越界

调用append函数必须用原来的切片变量接收返回值
原因:举个例子,搜狐公司开始两个人,公司只有两个位置,后来又来一个员工,位置不够了,那么公司搬家,搬到更大的地方去,这个公司还是这个公司。
append函数同理,在原来底层数组放不下的时候,Go就会把原来的底层数组(公司地址)换一个

s = append(s,"少")

在使用append时候,这个切片没有必要先初始化,可以直接用。
注意:通过var声明的零值切片可以在append()函数直接使用,无需初始化。

var s []int
s = append(s, 1, 2, 3)

没有必要像下面的代码一样初始化一个切片再传入append()函数使用

s := []int{}  // 没有必要初始化
s = append(s, 1, 2, 3)

var s = make([]int)  // 没有必要初始化
s = append(s, 1, 2, 3)

使用copy()函数复制切片
首先我们来看一个问题:

func main() {
	a := []int{1, 2, 3, 4, 5}
	b := a
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(b) //[1 2 3 4 5]
	b[0] = 1000
	fmt.Println(a) //[1000 2 3 4 5]
	fmt.Println(b) //[1000 2 3 4 5]
}

由于切片是引用类型,所以a和b其实都指向了同一块内存地址。修改b的同时a的值也会发生变化。

Go语言内建的copy()函数可以迅速地将一个切片的数据复制到另外一个切片空间中,copy()函数的使用格式如下:

copy(destSlice, srcSlice []T)

其中:

  • srcSlice: 数据来源切片
  • destSlice: 目标切片

举个例子:

func main() {
	// copy()复制切片
	a := []int{1, 2, 3, 4, 5}
	c := make([]int, 5, 5)
	copy(c, a)     //使用copy()函数将切片a中的元素复制到切片c
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1 2 3 4 5]
	c[0] = 1000
	fmt.Println(a) //[1 2 3 4 5]
	fmt.Println(c) //[1000 2 3 4 5]
}

从切片中删除元素
Go语言中并没有删除切片元素的专用方法,我们可以使用切片本身的特性来删除元素。 代码如下:

func main() {
	// 从切片中删除元素
	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]
}

总结一下就是:要从切片a中删除索引为index的元素,操作方法是a = append(a[:index], a[index+1:]...)

指针:

  • &取地址
  • *根据地址取值
//取地址
a := 12
p := &a
fmt.Printf(p)
//是一个16进制的内存地址
fmt.Printf("%T\n",p)//*int代表int型指针
//根据地址p 取值
m := *p
fmt.Printf(m)//输出12

New函数:
用来申请一块内存地址

//错误示范:
var a = *int//这里虽然定义的是一个int型指针,但是却是nil指针
//所以我们需要用到new函数
var a = new(int)//这时a才是一个真正的不是空的内存地址
*a = 100
fmt.Printf(*a)

make和new的区别:

  1. make和new都是用来申请内存的
  2. new很少用,一般用来给基本数据类型申请内存的:string、int,返回的是对应类型的指针
  3. make是用来给slice,map,chan申请内存的,返回的是对应三个类型的本身。

map

定义:

var a map[int]string  //定义了一个map集合 key是int型 value是string型
//初始化
a = make(map[int]string,10) //这里10是容量,键值对个数,估算好容量避免不够在要
a[3] = "大大"

map基本使用:
map中的数据都是成对出现的,map的基本使用示例代码如下:

func main() {
	scoreMap := make(map[string]int, 8)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	fmt.Println(scoreMap)
	fmt.Println(scoreMap["小明"])
	fmt.Printf("type of a:%T\n", scoreMap)
}
输出:

//map[小明:100 张三:90]
//100
//type of a:map[string]int

//map也支持在声明的时候填充元素,例如:
func main() {
	userInfo := map[string]string{
		"username": "沙河小王子",
		"password": "123456",
	}
	fmt.Println(userInfo) //
}

判断某个键是否存在

value, ok := map[key]

map的遍历
Go语言中使用for range遍历map。

func main() {
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	for k, v := range scoreMap {
		fmt.Println(k, v)
	}
}

但我们只想遍历key的时候,可以按下面的写法:

func main() {
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	for k := range scoreMap {
		fmt.Println(k)
	}
}

注意遍历map时的元素顺序与添加键值对的顺序无关。
使用delete()函数删除键值对
使用delete()内建函数从map中删除一组键值对,delete()函数的格式如下:

delete(map, key)

其中,

  1. map:表示要删除键值对的map
  2. key:表示要删除的键值对的键
    示例代码如下:
func main(){
	scoreMap := make(map[string]int)
	scoreMap["张三"] = 90
	scoreMap["小明"] = 100
	scoreMap["娜扎"] = 60
	delete(scoreMap, "小明")//将小明:100从map中删除
	for k,v := range scoreMap{
		fmt.Println(k, v)
	}
}

按照指定顺序遍历map

func main() {
	rand.Seed(time.Now().UnixNano()) //初始化随机数种子

	var scoreMap = make(map[string]int, 200)

	for i := 0; i < 100; i++ {
		key := fmt.Sprintf("stu%02d", i) //生成stu开头的字符串
		value := rand.Intn(100)          //生成0~99的随机整数
		scoreMap[key] = value
	}
	//取出map中的所有key存入切片keys
	var keys = make([]string, 0, 200)
	for key := range scoreMap {
		keys = append(keys, key)
	}
	//对切片进行排序
	sort.Strings(keys)
	//按照排序后的key遍历map
	for _, key := range keys {
		fmt.Println(key, scoreMap[key])
	}
}

元素为map类型的切片
下面的代码演示了切片中的元素为map类型时的操作:

func main() {
	var mapSlice = make([]map[string]string, 3)
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
	fmt.Println("after init")
	// 对切片中的map元素进行初始化
	mapSlice[0] = make(map[string]string, 10)
	mapSlice[0]["name"] = "小王子"
	mapSlice[0]["password"] = "123456"
	mapSlice[0]["address"] = "沙河"
	for index, value := range mapSlice {
		fmt.Printf("index:%d value:%v\n", index, value)
	}
}

值为切片类型的map
下面的代码演示了map中值为切片类型的操作:

func main() {
	var sliceMap = make(map[string][]string, 3)
	fmt.Println(sliceMap)
	fmt.Println("after init")
	key := "中国"
	value, ok := sliceMap[key]
	if !ok {
		value = make([]string, 0, 2)
	}
	value = append(value, "北京", "上海")
	sliceMap[key] = value
	fmt.Println(sliceMap)
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值