【GO 编程语言】切片与Map

news2025/1/22 9:21:45

切片与Map


文章目录

  • 切片与Map
  • 一、切片 Slice
    • 1.定义切片
    • 2.make 函数创建切片
    • 3.切片扩容与遍历
    • 4.在已有数组上创建切片
    • 5.切片是引用类型
    • 7.深拷贝、浅拷贝
  • 二、Map
    • 1.Map 初始化
    • 2.map 的使用
    • 3.map 的遍历
    • 4.map 结合 slice


在这里插入图片描述


一、切片 Slice

1.定义切片

Go 语言切片是对数组的抽象。

Go数组的长度不可改变,在特定场景中这样的集合就不太适用,Go中提供了一种灵活,功能强悍的内置类型切片(“动态数组”),与数组相比切片的长度是不固定的,可以追加元素,在追加时可能使切片的容量增大

切片是一种方便、灵活且强大的包装器,切片本身没有任何数据,他们只是对现有数组的引用。

切片与数组相比,不需要设定长度,在 [ ] 中不用设定值,相对来说比较自由

从概念上面来说 slice 像一个结构体,这个结构体包含了三个元素:

  • 指针:指向数组中 slice 指定的什始位置
  • 长度:即slicc的长度
  • 最大长度:也就是 slice 刀始位置到数组的最后位置的长度
package main

import "fmt"

func main() {
	// 数组的长度一旦定义就是不可改变的
	arr := [4]int{1, 2, 3, 4}
	fmt.Println(arr)

	// 定义切片、长度就是可变的
	var c1 []int
	fmt.Println(c1)
	if c1 == nil {
		fmt.Println("切片为空")
	}

	c2 := []int{1, 2, 3, 4, 5}
	fmt.Println(c2)
	fmt.Printf("%T,%T\n", c1, arr) // []int,[4]int

	fmt.Println(c2[0])
	fmt.Println(c2[1])
}

在这里插入图片描述

2.make 函数创建切片

  • 使用 make( ) 函数来创建切片
  • make( [ ] T,length,capacity)
  • 切片是可索引的,并且可以由 len( ) 方法获取长度。
  • 切片提供了计算容量的方法 cap( ) 可以测量切片最长可以达到多少。
package main

import "fmt"

func main() {
	// make( [ ] T,length,capacity)
	a1 := make([]int, 5, 10)
	fmt.Println(a1)
	fmt.Println("长度:", len(a1))
	fmt.Println("容量:", cap(a1))
	//容量 10 长度5
	//虽然容量为10,但是可以进行操作的取决于长度5
	a1[1] = 66
	a1[6] = 99
	fmt.Println(a1)

}

在这里插入图片描述

3.切片扩容与遍历

package main

import "fmt"

func main() {
	// 扩容
	a1 := make([]int, 5, 10)
	a1 = append(a1, 1, 2, 3)
	fmt.Println(a1)
	// 如果切片中的数据超过了规定的容量,那么他就会自动扩容
	a2 := make([]int, 0, 5)
	a2 = append(a2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
	fmt.Println(a2)

	a3 := []int{6, 6, 6, 6, 6, 6}
	// 将切片a3追加到切片a1
	a1 = append(a1, a3...)
	fmt.Println(a1)

	for i := 0; i < len(a1); i++ {
		fmt.Println(a1[i])
	}
	fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	for _, v := range a1 {
		fmt.Println(v)
	}

}

在这里插入图片描述
在这里插入图片描述
扩容的内存分析

package main

import "fmt"

func main() {

	a1 := []int{1, 2, 3}
	fmt.Println(a1)
	fmt.Printf("len:%d,cap:%d\n", len(a1), cap(a1)) //len:3,cap:3
	fmt.Printf("%p\n", a1)

	a1 = append(a1, 4, 5, 6)
	fmt.Println(a1)
	fmt.Printf("len:%d,cap:%d\n", len(a1), cap(a1)) //len:6,cap:6
	fmt.Printf("%p\n", a1)
	a1 = append(a1, 7, 8, 9, 10)
	fmt.Println(a1)
	fmt.Printf("len:%d,cap:%d\n", len(a1), cap(a1)) //len:6,cap:6
	fmt.Printf("%p\n", a1)
	a1 = append(a1, 10, 11, 12, 13)
	fmt.Println(a1)
	fmt.Printf("len:%d,cap:%d\n", len(a1), cap(a1)) //len:6,cap:6
	fmt.Printf("%p\n", a1)

}


在这里插入图片描述

  • 每个切片引用了一个底层数组
  • 切片本身不存储任何数据,都是这个底层数组存储,所以修改切片也就是修改这个数组中的数据
  • 当向切片中添加数据时,如果没有超过容量,直接添加。如果超过了容量,自动扩容,容量成倍增加。

实现原理是使用 Copy 方法

package main

import "fmt"

func main() {

	nums := []int{1, 2, 3}
	fmt.Printf("len:%d,cap:%d slice=%v\n", len(nums), cap(nums), nums) //len:3,cap:3

	/* 创建切片 nums1 是之前切片的两倍容量 */
	nums1 := make([]int, len(nums), (len(nums))*2)

	/* 拷贝 nums 的内容到 nums1 */
	copy(nums1, nums)
	fmt.Printf("len:%d,cap:%d slice=%v\n", len(nums1), cap(nums1), nums1)

}

在这里插入图片描述

  • 切片一旦扩容,就重新指向一个新的底层数组

4.在已有数组上创建切片

从已有的数组上,直接创建切片,该切片的底层数组就是当前的数组,长度是从 start 带 end 切割的数据量,但是容量是从start 到数组的末尾

package main

import "fmt"

func main() {
	arr := [10]int{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

	fmt.Println("通过数组创建切片")
	// arr[start,end] 包含start:end不包含
	a1 := arr[:5]   // 1~5
	a2 := arr[5:8]  // 6~8
	a3 := arr[8:10] // 8~10
	a4 := arr[:]    // 1~10

	fmt.Println(a1)
	fmt.Println(a2)
	fmt.Println(a3)
	fmt.Println(a4)

	// 改数组中的元素,则切片中元素也会改,因为他们指向同一存储空间
	arr[0] = 99
	fmt.Println(arr)
	fmt.Println(a1)

	a1[1] = 100
	fmt.Println(arr)
	fmt.Println(a1)

	fmt.Printf("%p\n", a1)
	// arr 是一个数组,所以需要用 & 取出地址
	fmt.Printf("%p\n", &arr)

	fmt.Printf("len:%d,cap:%d\n", len(a1), cap(a1))
	fmt.Printf("len:%d,cap:%d\n", len(a2), cap(a2))
	fmt.Printf("len:%d,cap:%d\n", len(a3), cap(a3))
	fmt.Printf("len:%d,cap:%d\n", len(a4), cap(a4))

		// 进行扩容,如果超过了容量,则赋值生成新的一个数组
	a1 = append(a1, 1, 1, 1, 1, 1, 1, 1)
	fmt.Println(arr)
	fmt.Println(a1)

	// 切片改了数组没有发生变化
	a1[0] = 1000
	fmt.Println(arr)
	fmt.Println(a1)
	fmt.Printf("%p\n", a1)
	// arr 是一个数组,所以需要用 & 取出地址
	fmt.Printf("%p\n", &arr)

}


在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

5.切片是引用类型

package main

import "fmt"

func main() {

	// 数组:值类型——拷贝
	arr1 := [3]int{1, 2, 3} // 数组
	arr2 := arr1
	fmt.Println(arr1, arr2)
	// 修改arr2不会影响arr1
	arr2[2] = 888
	fmt.Println(arr1, arr2)
	fmt.Println(">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>")
	// 切片:引用类型——地址
	arr3 := []int{1, 2, 3, 4, 5, 6}
	arr4 := arr3
	fmt.Println(arr3, arr4)
	// 修改arr4会对arr4也进行修改
	arr4[2] = 666
	fmt.Println(arr3, arr4)
}

在这里插入图片描述

7.深拷贝、浅拷贝

深拷贝:拷贝的是数据本身

  • 值类型的数据,默认都是
    • 深拷贝:array、int、 float、string、 bool、sturct
    • 浅拷贝:拷贝的是数据的地址,会导致多个变量指向同一块内存。
  • 引用类型的数据,默认都是浅拷贝: slice、map
  • 因为切片是引用类型的数据,直接拷贝的是地址
package main

import "fmt"

func main() {

	s1 := []int{1, 2, 3, 4, 5}
	s2 := make([]int, 0, 0)

	// 通过 赋值的方式实现切片的深拷贝
	for i := 0; i < len(s1); i++ {
		s2 = append(s2, s1[i])
	}
	fmt.Println(s1)
	fmt.Println(s2)

	s2[1] = 88
	fmt.Println(s1)
	fmt.Println(s2)

	// copy
	s3 := []int{4, 5, 6, 7, 8}
	fmt.Println(s1)
	fmt.Println(s3)

	copy(s1, s3)
	fmt.Println(s1)
	fmt.Println(s3)
}

在这里插入图片描述

二、Map

  • Map是一种无序的键值对的集合。Map最重要的一点是通过 key来快速检索数据, key类似于索引,指向数据的值。

  • Map是一种集合,所以我们可以像迭代数组和切片那样迭代它。不过,Map是无序的,我们无法决定它的返回顺序。

  • Map 也是引用类型.

1.Map 初始化

package main

import "fmt"

func main() {

	/*
		声明变量,默认 map 是 nil
		var map_variable map[key_data_type]value_data_type
		使用 make 函数
		map_variable := make(map[key_data_type]value_data_type)
	*/
	// map 类型的定义: map[key]value nil
	// 第一种方法:通过声明变量
	var map1 map[int]string // 为 true,则为未创建
	// 第二种:使用make
	var map2 = make(map[string]string) // true nil 为创建    //map[] 创建
	// 第三种:创建时直接赋值
	var map3 = map[string]int{"Go": 99, "Python": 88, "C": 66}

	map2["hello1"] = "hello1"
	map2["hello2"] = "hello2"
	map2["hello3"] = "hello3"
	map2["hello4"] = "hello4"

	fmt.Println(map1)
	fmt.Println(map2)
	fmt.Println(map3)

	fmt.Println(map1 == nil)
	fmt.Println(map2 == nil)

}

在这里插入图片描述

2.map 的使用

package main

import "fmt"

func main() {

	// 创建 map
	var map1 map[int]string //nil
	map1 = make(map[int]string)

	// 存储键值对,给键值对赋值
	map1[1] = "guan01"
	map1[2] = "guan02"
	map1[3] = "guan03"

	fmt.Println(map1)

	// 获取 map 的数据
	// 根据 key,来获取 value
	// key 不存在,则获取默认的零值
	fmt.Println(map1[1])
	fmt.Println(map1[2])
	fmt.Println(map1[3])
	fmt.Println(map1[4])

	// 可以通过 ok-idiom 来判断 key value 是否存在
	value, ok := map1[1]
	if ok == true {
		fmt.Println("map key存在value", value)
	} else {
		fmt.Println("map key不存在")
	}

	value1, ok := map1[4]
	if ok == true {
		fmt.Println("map key存在value", value1)
	} else {
		fmt.Println("map key不存在")
	}

	// 修改数据
	map1[1] = "luo01"
	fmt.Println(map1)

	// map 删除 delete
	delete(map1, 2)
	fmt.Println(map1)

	// 如果 key 不存在就是新增,存在就是修改
	map1[6] = "luo06"
	fmt.Println(map1)

}

在这里插入图片描述

3.map 的遍历

使用map过程中需要注意的几点:

  • map是无序的,每次打印出来的map都会不一样,它不能通过index获取,而必须通过key获取
  • map的长度是不固定的,也就是和 slice 一样,也是 一种引用类型
  • 内置的 len 函数同样适用于 map,这回 map 拥有的 key 的数量
  • map的key可以是所有可比较的类型,如布尔型、整数型、浮点型、宁符串….
package main

import "fmt"

func main() {

	var map1 = map[string]int{"Go": 99, "Python": 88, "Java": 66}
	map2 := map1
	// 多运行几次发现每次遍历的结果都不同,map是无序的
	for k := range map1 {
		fmt.Println(k, map1[k])
	}
	// 修改map2,发现map1 被修改了
	map2["Go"] = 0
	fmt.Println(map1)
}


在这里插入图片描述

4.map 结合 slice

需求:

  • 1.创建 map 来存储人的信息,如name、age、sex、addr
  • 2.每个 map 存一个人的信息
  • 3.将这些 map 存入到 slice 中
  • 4.打印遍历输出
package main

import "fmt"

func main() {

	user1 := make(map[string]string)
	user1["name"] = "guan001"
	user1["age"] = "8"
	user1["sex"] = "男"
	user1["addr"] = "广西"

	user2 := make(map[string]string)
	user2["name"] = "guan002"
	user2["age"] = "9"
	user2["sex"] = "男"
	user2["addr"] = "广东"

	user3 := map[string]string{"name": "guan03", "age": "10", "sex": "女", "addr": "四川"}

	fmt.Println(user1)
	fmt.Println(user2)
	fmt.Println(user3)

	userDatas := make([]map[string]string, 0, 3) //[]map[string]string为类型,0为长度,3为容量
	userDatas = append(userDatas, user1)
	userDatas = append(userDatas, user2)
	userDatas = append(userDatas, user3)

	fmt.Println(userDatas)

	for _, v := range userDatas {
		fmt.Printf("name:%s\n", v["name"])
		fmt.Printf("age:%s\n", v["age"])
		fmt.Printf("sex:%s\n", v["sex"])
		fmt.Printf("addr:%s\n", v["addr"])
		fmt.Println()
	}
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/527231.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

设置ELK集群账号密码

一、设置ELK集群账号密码 切换到es用户 主节点生成证书 cd /home/es/elasticsearch-7.6.2/bin ./elasticsearch-certutil cert -out config/elastic-certificates.p12 -pass "" 将主节点证书发给其他两个节点 修改配置文件&#xff0c;启用x-pack&#xff1a;cat /…

Linux指令运行原理和权限

Linux指令运行原理和权限 一.命名行解释器二.权限1.用户分类2.什么是权限3.增删权限4.更改权限的拥有者5.三个概念1.权限掩码2.目录权限3.粘滞位 三.权限总结 一.命名行解释器 那么命令行解释器存在的意义&#xff1a;1.进行命令的解释。2.保护os&#xff0c;对于非法的请求&am…

TimesNet:用于一般时间序列分析的时间二维变化模型

摘要 时间序列分析在天气预报、异常检测和动作识别等广泛应用中具有极其重要的意义。本文重点研究时间变量建模&#xff0c;这是广泛分析任务的共同关键问题。以前的方法试图直接从一维时间序列完成此操作&#xff0c;由于错综复杂的时间模式&#xff0c;这极具挑战性。基于对…

使用flask获取树莓派摄像头监控视频

目录 1、安装flask库 2、使用flask打开网页传输视频 2.1 在树莓派终端桌面上&#xff0c;新建一个flask文件夹 2.2 在flask文件夹里面&#xff0c;新建一个template文件夹和app.py文件 2.3 在template文件夹里面&#xff0c;新建一个index.html文件 2.4 使用flask运行代码…

【半小时入门vue】最容易理解的vue入门方式

半小时入门vue 前言&#xff08;&#xff01;important&#xff09;学习vue的前提什么是vue&#xff1f;vue的引入方式实例化一个对象和创建一个对象实例化一个vue对象模板语法1.插值表达式2.v-text和v-html指令3.v-bind指令4.v-on指令5.v-model指令6.v-if和v-show指令7.v-for指…

AD-STM32

AD-STM32 ADC (Analog-Digital Converter) 模拟-数字转换器A DC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量&#xff0c;建立模拟电路到数字电路的桥梁 12位逐次逼近型ADC&#xff0c;1us转换时间 输入电压范围: 0-3.3V&#xff0c;转换结果范围: 0~409518个输…

MySQL内幕揭秘:探索MySQL调优指南,解锁MySQL的强大功能

1、MySQL大事记 1994年&#xff1a;Michael Widenius和David Axmark创建了MySQL AB。 1995年&#xff1a;MySQL从最初的beta版本发布&#xff0c;成为一款开源软件。 1997年&#xff1a;MySQL发行版本3.21&#xff0c;并成为了第一个支持多个存储引擎的数据库管理系统。 2000年…

uniapp 地图组件(map)的使用总结

总结一下本次在uniapp中使用map遇到的一些问题 文章分别是基础 定位图标 获取自身经纬度 通过经纬度获取当时城市信息 首先先看成品 首先引入map组件 <template><view class"content"><map style"width: 100%; height: 90vh;" :layer-…

通过云函数搭建内地可用的OpenAI代理(腾讯云centos系统)

需求&#xff1a; 大陆内地云服务器无须搭梯子&#xff0c;无须NGINX反向代理访问openAI。 背景&#xff1a; 平时工作环境是局域网&#xff0c;不方便分享给朋友用&#xff0c;即使不是局域网也不可能一直开着自己的电脑啦&#xff0c;于是想着给弄到云服务器上。 一般来说&…

diff命令和vimdiff命令

文章目录 diff命令基本用法选项示例 vimdiff命令命令格式选项说明常用操作 diff命令 diff命令是一个文本比较工具&#xff0c;用于比较两个文件的内容&#xff0c;它会逐行比较两个文件的内容并输出它们之间的差异。下面是diff命令的常用选项和用法&#xff1a; 基本用法 比…

数据信息汇总的7种基本技术总结

数据汇总是一个将原始数据简化为其主要成分或特征的过程&#xff0c;使其更容易理解、可视化和分析。本文介绍总结数据的七种重要方法&#xff0c;有助于理解数据实质的内容。 1、集中趋势:平均值&#xff0c;中位数&#xff0c;众数 集中趋势是一种统计测量&#xff0c;目的…

RFID系统简介:优点、应用与发展前景

一、介绍RFID系统 RFID系统全称是Radio Frequency Identification&#xff0c;是一种通过电磁场自动识别标记&#xff08;Tag或RFID标签&#xff09;并读取相关数据的技术。与条形码技术相比&#xff0c;RFID系统最大的特点就是可以自动识别、无须接触扫描&#xff0c;并且可以…

MySQL报错:Got an error reading communication packets

error reading 关闭连接 通常一旦连接建立&#xff0c;MySQLD端的线程会堵塞在poll上&#xff0c;而poll的就是连接socket的fd&#xff0c;等待读取命令&#xff0c;也就是读取MySQL net packet的header。同时如果是poll timeout超时则设置为SOCKET_ETIMEDOUT 这就是我们平时说…

ResNet 原论文及原作者讲解

ResNet 论文摘要1. 引入2. 相关工作残差表示快捷连接 3. 深度残差学习3.1. 残差学习3.2. 快捷恒等映射3.3. 网络体系结构普通网络 plain network残差网络 residual network 3.4. 实施 4. 实验4.1. ImageNet分类普通的网络 plain network残差网络 residual network恒等vs.快捷连…

ribbon的使用

什么是ribbon Ribbon是Netflix公司提供的一个基于HTTP和TCP的客户端负载均衡工具。 Spring Cloud Ribbon是基于Netflix Ribbon 实现的一套客户端的负载均衡工具&#xff0c;Ribbon客户端组件提供一系列的完善的配置&#xff0c;如超时&#xff0c;重试等。通过Load Balancer获取…

随笔:mysql的主主同步

背景&#xff1a; nginx负载均衡和双击热备下&#xff0c;要求支持mysql的test库的主主同步&#xff0c;同时需要豁免特定的三张配置表。 实现步骤&#xff1a; 1. 查看防火墙是否是关闭状态。systemctl status firewalld 2. 修改配置&#xff0c;增加以下内容。vi /etc/my.cnf…

利用Github Action备份Docker容器中的数据库

利用Github Action备份Docker容器中的数据库 本文方案仅供技术参考与娱乐&#xff01; 前言 数据很重要&#xff0c;所以我们要经常备份。 那么怎么备份呢&#xff1f;假如我们使用云厂商的数据库&#xff0c;里面已经自带了快照和备份功能了&#xff0c;只要你愿意花钱&…

golang 使用 OpenTelemetry 实现跨服务 全链路追踪

使用 OpenTelemetry 链路追踪说明 工作中常常会遇到需要查看服务调用关系,比如用户请求了一个接口接口会调用其他grpc,http接口,或者内部的方法这样的调用链路,如果出现了问题,我们需要快速的定位问题,这时候就需要一个工具来帮助我们查看调用链路OpenTelemetry就是这样一个工…

力扣总结,深度优先题

LCP 67. 装饰树 –链接– 中等 10 相关企业 力扣嘉年华上的 DIY 手工展位准备了一棵缩小版的 二叉 装饰树 root 和灯饰&#xff0c;你需要将灯饰逐一插入装饰树中&#xff0c;要求如下&#xff1a; 完成装饰的二叉树根结点与 root 的根结点值相同 若一个节点拥有父节点&#x…

用Java开发的建站神器JPress

什么是 JPress &#xff1f; JPress 是一个使用 Java 开发的、类似 WordPress 的产品&#xff0c;支持多站点、多语种自动切换等。&#xff08;JPress 始于2015 年&#xff09; 目前已经有 10w 网站使用 JPress 进行驱动&#xff0c;其中包括多个政府机构&#xff0c;200 上市公…