4、数组、切片、map、channel

news2024/11/15 20:44:12

目录

  • 一、数组
  • 二、切片
  • 三、map
  • 四、channel
  • 五、引用类型

一、数组

  • 数组
    • 数组是块连续的内存空间,在声明的时候必须指定长度,且长度不能改变
    • 所以数组在声明的时候就可以把内存空间分配好,并赋上默认值,即完成了初始化
    • 数组的地址就是首元素的地址
  • 一维数组初始化
func main() {
	var arr1 [5]int = [5]int{} //数组必须指定长度和类型,且长度和类型指定后不可改变
	var arr2 = [5]int{}
	var arr3 = [5]int{3, 2}            //给前2个元素赋值
	var arr4 = [5]int{2: 15, 4: 30}    //指定index赋值
	var arr5 = [...]int{3, 2, 6, 5, 4} //根据{}里元素的个数推断出数组的长度
	var arr6 = [...]struct {
		name string
		age  int
	}{{"Tom", 18}, {"Jim", 20}} //数组的元素类型由匿名结构体给定
}
  • 二维数组初始化
func main() {
	//5行3列,只给前2行赋值,且前2行的所有列还没有赋满
	var arr1 = [5][3]int{{1}, {2, 3}}
	//第1维可以用...推测,第2维不能用...
	var arr2 = [...][3]int{{1}, {2, 3}}
}
  • 访问数组里的元素
    • 通过index访问
      • 首元素 arr[0]
      • 末元素 arr[len(arr)-1]
    • 访问二维数组里的元素
      • 位于第三行第四列的元素 arr[2][3]
func main() {
	//遍历数组里的元素
	//i, ele := range的理解
	//	-> range返回2个,1个是索引i,1个是元素ele
	//	-> 将range的返回用来声明并初始化i和ele
	for i, ele := range arr {
		fmt.Printf("index=%d, element=%d\n", i, ele)
	}
	//或者这样遍历数组
	for i := 0; i < len(arr); i++ { //len(arr)获取数组的长度
		fmt.Printf("index=%d, element=%d\n", i, arr[i])
	}
	//遍历二维数组
	for row, array := range arr { //先取出某一行
		for col, ele := range array { //再遍历这一行
			fmt.Printf("arr[%d][%d]=%d\n", row, col, ele)
		}
	}
}
  • 通过for range遍历数组时取得的是数组里每一个元素的拷贝
func main() {
	arr := [...]int{1, 2, 3}
	for i, ele := range arr { //ele是arr中元素的拷贝
		arr[i] += 8                              //修改arr里的元素,不影响ele
		fmt.Printf("%d %d %d\n", i, arr[i], ele) //0 9 1
		ele += 1                                 //修改ele不影响arr
		fmt.Printf("%d %d %d\n", i, arr[i], ele) //0 9 2
	}
	for i := 0; i < len(arr); i++ {
		fmt.Printf("%d %d\n", i, arr[i])
		//0 9
		//1 10
		//2 11
	}
}
  • 数组的cap和len
    • 在数组上调用cap()函数表示capacity容量,即给数组分配的内存空间可以容纳多少个元素;
    • len()函数代表length长度,即目前数组里有几个元素;
    • 由于数组初始化之后长度不会改变,不需要给它预留内存空间,所以len(arr)==cap(arr);
    • 对于多维数组,其cap和len指第一维的长度
  • 数组的参数传递
    • 数组的长度和类型都是数组类型的一部分,函数传递数组类型时这两部分都必须吻合;
    • go语言没有按引用传参,全都是按值传参,即传递数组实际上传的是数组的拷贝,当数组的长度很大时,仅传参开销都很大;
    • 如果想修改函数外部的数组,就把它的指针(数组在内存里的地址)传进来
// 值传递拷贝
func arrPoint(arr [5]int) {
	fmt.Println(arr[0]) //1
	arr[0] += 10
	fmt.Println(arr[0]) //11
}

// 指针传递地址
func arrPPoint(arr *[5]int) {
	fmt.Println(arr[0]) //1
	arr[0] += 10
	fmt.Println(arr[0]) //11
}

func main() {
	var crr [5]int = [5]int{1, 2, 3, 6, 9}
	arrPoint(crr)
	fmt.Println(crr[0]) //1

	arrPPoint(&crr)
	fmt.Println(crr[0]) //11
}

//

// 参数必须是长度为5的int型数组(注意长度必须是5)
func update_array1(arr [5]int) {
	fmt.Printf("array in function, address is %p\n", &arr[0])
	arr[0] = 888
}

func update_array2(arr *[5]int) {
	fmt.Printf("array in function, address is %p\n", &((*arr)[0]))
	arr[0] = 888 //因为传的是数组指针,所以直接在原来的内存空间上进行修改
}

// range遍历是元素拷贝
func forRange() {
	arr := [...]int{1, 2, 3, 4, 5}
	for _, ele := range arr { // ele是arr里元素的拷贝
		ele += 10
	}
	fmt.Println(arr) //[1 2 3 4 5]
}

二、切片

  • 切片概念:切片是一个结构体,包含三个成员变量,array指向一块连续的内存空间,cap表示这块内存的大小,len表示目前该内存里存储了多少元素
    在这里插入图片描述
type slice struct {
    array unsafe.Pointer
    len int
    cap int
}
  • 切片的初始化
func main() {
	var s []int              //切片声明,array=nil,len=cap=0
	s = []int{}              //初始化,len=cap=0
	s = make([]int, 3)       //初始化,len=cap=3
	s = make([]int, 3, 5)    //初始化,len=3,cap=5
	s = []int{1, 2, 3, 4, 5} //初始化,len=cap=5
	s2d := [][]int{
		{1}, {2, 3}, //二维数组各行的列数相等,但二维切片各行的len可以不等
	}
}
  • 切片的特点
    • 切片相对于数组最大的特点就是可以追加元素,可以自动扩容
    • 追加的元素放到预留的内存空间里,同时len加1
    • 如果预留空间已用完,则会重新申请一块更大的内存空间,capacity大约变成之前的2倍(cap<1024)或1.25倍(cap>1024);把原内存空间的数据拷贝过来,在新内存空间上执行append操作
func sliceAppend() {
	s := make([]int, 3, 5)
	fmt.Println(len(s), cap(s)) // 3 5
	s = append(s, 100)
	fmt.Println(len(s), cap(s)) // 4 5
	s = append(s, 100)
	fmt.Println(len(s), cap(s)) // 5 5
	s = append(s, 100)
	fmt.Println(len(s), cap(s)) // 6 10
}

// 2倍扩容验证
// cap 5 -> 10
// cap 10 -> 20
// cap 20 -> 40
// cap 40 -> 80
// cap 80 -> 160
func coef_cap() {
	s := make([]int, 0, 5)
	preCap := cap(s)
	for i := 0; i < 100; i++ {
		s = append(s, 0)
		curCap := cap(s)
		if curCap > preCap {
			fmt.Printf("cap %d -> %d\n", preCap, curCap)
			preCap = curCap
		}
	}
}
  • 截取子切片:子切片与目切片的内存共享与内存分离
func sub_slice() {
	arr := make([]int, 3, 5)
	crr := arr[0:2] //左闭右开
	crr[1] = 8
	fmt.Println(arr) // [0 8 0] 子切片与母切片共享内存空间

	crr = append(crr, 9)
	fmt.Println(arr)                        // [0 8 9]
	fmt.Printf("%p %p\n", &arr[0], &crr[0]) // 0xc0000103f0 0xc0000103f0

	crr = append(crr, 9)
	crr = append(crr, 9)

	// 此时子切片申请一片新的内存,把老数据先拷贝过来,在新内存上执行append操作
	// 此时子切片已经与母切片内存分离
	crr = append(crr, 9)
	fmt.Println(arr)                        // [0 8 9]
	fmt.Println(crr)                        // [0 8 9 9 9]
	fmt.Printf("%p %p\n", &arr[0], &crr[0]) // 0xc0000103f0 0xc000014230
}
  • 子切片传参
    • go语言函数传参,传的都是值,即传切片会把切片的{arrayPointer, len, cap}这3个字段拷贝一份传进来
    • 由于传的是底层数组的指针,所以可以直接修改底层数组里的元素
func update_slice(s []int) {
	s[0] = 100
}

func main() {
	s := []int{1, 2, 3}
	update_slice(s)
	fmt.Println(s) // [100 2 3]
}

三、map

  • map的底层原理:go map的底层实现是hash table,根据key查找value的时间复杂度是O(1)

在这里插入图片描述

  • map的初始化
func main() {
	var m map[string]int                  //声明map,指定key和value的数据类型
	m = make(map[string]int)              //初始化,容量为0
	m = make(map[string]int, 5)           //初始化,容量为5。强烈建议初始化时给一个合适的容量,减少扩容的概率
	m = map[string]int{"语文": 0, "数学": 39} //初始化时直接赋值
}
  • 获取map的长度:len(m)获取map的长度(map中的key数量),go不支持对map上执行cap函数
  • 添加和删除key
func main() {
	m["英语"] = 59    //往map里添加key-value对
	m["英语"] = 70    //会覆盖之前的值
	delete(m, "数学") //从map里删除key-value对
}
  • map读取key对应的value值:读取key对应的value时,如果key不存在,则返回value类型的默认值,所以强烈建议先判断key是否存在
func main() {
	if value, exists := m["语文"]; exists {
		fmt.Println(value)
	} else {
		fmt.Println("map里不存在[语文]这个key")
	}
}
  • map遍历:多次遍历map返回的顺序是不一样的,但相对顺序是一样的,因为每次随机选择一个开始位置,然后顺序遍历
func main() {

	m := make(map[string]int)
	m["a"] = 10
	m["b"] = 20
	m["c"] = 30

	//遍历map
	for key, value := range m {
		value += 100 //range的value是值拷贝
		fmt.Printf("%s=%d\n", key, value)
		//a=110
		//b=120
		//c=130
	}
	fmt.Println(m) //map[a:10 b:20 c:30]

	for key := range m {
		m[key] += 200 //使用key直接对map的原数据进行操作
	}
	fmt.Println(m) //map[a:210 b:220 c:230]

}

四、channel

  • channel底层
    • channel(管道)底层是一个环形队列(先进先出),send(插入)和recv(取走)从同一个位置沿同一个方向顺序执行
    • sendx表示最后一次插入元素的位置,recvx表示最后一次取走元素的位置
      在这里插入图片描述
  • channel初始化
func main() {
	var ch chan int        //声明
	ch = make(chan int, 8) //初始化,环形队列里可容纳8个int
}
  • channel的len和cap
func main() {
	var ch chan int
	fmt.Printf("ch is nil %t\n", ch == nil)  //ch is nil true
	fmt.Printf("len of ch is %d\n", len(ch)) //len of ch is 0

	ch = make(chan int, 10)
	fmt.Printf("len of ch is %d\n", len(ch)) //len of ch is 0
	fmt.Printf("cap of ch is %d\n", cap(ch)) //cap of ch is 10
}
  • channel的cap上限:达到cap的上限后,继续send会导致管道阻塞
func main() {
	ch := make(chan int, 10)
	for i := 0; i < 10; i++ {
		ch <- 3
	}
	fmt.Printf("len of ch is %d\n", len(ch)) //len of ch is 10
	fmt.Printf("cap of ch is %d\n", cap(ch)) //cap of ch is 10
	ch <- 3                                  //阻塞
	fmt.Printf("len of ch is %d\n", len(ch)) //不会打印
	fmt.Printf("cap of ch is %d\n", cap(ch)) //不会打印
}
  • send和recv
func main() {
	ch := make(chan int, 8) //初始化,环形队列里可容纳8个int
	ch <- 1                 //往管道里写入(send)数据
	ch <- 2
	ch <- 3
	ch <- 4
	ch <- 5
	v := <-ch      //从管道里取走(recv)数据
	fmt.Println(v) //1
	v = <-ch
	fmt.Println(v) //2
}
  • channel遍历
    • 通过for range的方式遍历管道,遍历前必须先关闭close(ch)管道,禁止再写入元素;
    • 一旦close就不能再往管道里面追加元素
	close(ch) //遍历前必须先关闭管道,禁止再写入元素
	//遍历管道里剩下的元素
	for ele := range ch {
		fmt.Println(ele) //3 4 5
	}

五、引用类型

  • 引用类型
    • slice、map和channel是go语言里的3种引用类型,都可以通过make函数来进行初始化(申请内存分配)
    • 因为它们都包含一个指向底层数据结构的指针,所以称之为“引用”类型
    • 引用类型未初始化时都是nil,可以对它们执行len()函数,返回0

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

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

相关文章

Spring反射内置工具类ReflectionUtils

Spring反射内置工具类ReflectionUtils前言反射1&#xff0c;什么是反射2&#xff0c;反射的实现2.1获取class对象的三种实现2.1.1Object ——> getClass();2.1.2 任何数据对象&#xff08;包括数据基本类型&#xff09;都有一个静态的class属性通过Class类的静态方法&#x…

TX Text Control .NET 31.0 SP1 for WPF 企业版Crack

将文档编辑、创建和 PDF 生成添加到 WPF 应用程序。 TX Text Control for WPF Enterprise 是一个免版税、完全可编程的丰富编辑控件&#xff0c;它在专为 Visual Studio 设计的可重用组件中为开发人员提供了广泛的文字处理功能。它提供全面的文本格式&#xff0c;强大的邮件合并…

golang fmt.Sprintf(“%.2f“) 的舍入问题

首先&#xff0c;fmt.Sprintf("%.2f")使用的是banker rounding 而不是四舍五入&#xff0c;banker rounding 的定义如下&#xff08;来自百度百科&#xff09;&#xff1a;1.要求保留位数的后一位如果是4&#xff0c;则舍去。例如5.214保留两位小数为5.21。2.如果保留…

第四代英特尔至强重磅发布,芯片进入下半场:软硬加速、绿色可持续

编辑 | 宋慧 出品 | CSDN 云计算 2023 年的第二周&#xff0c;英特尔重磅发布其企业级芯片领域重要的产品——第四代英特尔 至强 可扩展处理器。作为数据中心处理器当之无愧的王牌产品&#xff0c;迄今为止&#xff0c;英特尔已经向全球客户交付了超8500万颗​至强可扩展处理器…

agent扩展-自定义外部加载路径

自定义classLoader实现加载外部jar, 以skywalking agent 类加载器为例子 整体思路 扩展findClass &#xff0c;解决loadClass可以查找到扩展findResource&#xff0c;解决getResources可以获取到资源 基本原理 ClassLoader loadClass的加载顺序 findLoadedClass 加载本地已经…

Spring Boot学习篇(十三)

Spring Boot学习篇(十三) shiro安全框架使用篇(五) 1 准备工作 1.1 在SysUserMapper.xml中书写自定义标签 <select id"findRoles" resultType"string">select name from sys_role where id (select roleid from sys_user_role where userid (S…

Matlab论文插图绘制模板第77期—对数刻度横向柱状图

在之前的文章中&#xff0c;分享了Matlab对数刻度柱状图的绘制模板&#xff1a; 进一步&#xff0c;再来看一下对数刻度横向柱状图的绘制模板。 先来看一下成品效果&#xff1a; 特别提示&#xff1a;Matlab论文插图绘制模板系列&#xff0c;旨在降低大家使用Matlab进行科研绘…

[WTL/ATL]_[初级]_[TreeView控件如何显示ToolTip]

场景 在开发界面程序时&#xff0c;CTreeViewCtrl(它实际内部封装的就是Win32的TreeView控件)一般会用来作为选择某些类型的树形菜单&#xff0c;点击某项的时候&#xff0c;右边能显示某些对应的数据。当这个控件的宽度固定时&#xff0c;有时候每行的文本项可能由于过长从而…

【图像分类】基于PyTorch搭建LSTM实现MNIST手写数字体识别(双向LSTM,附完整代码和数据集)

写在前面&#xff1a; 首先感谢兄弟们的关注和订阅&#xff0c;让我有创作的动力&#xff0c;在创作过程我会尽最大能力&#xff0c;保证作品的质量&#xff0c;如果有问题&#xff0c;可以私信我&#xff0c;让我们携手共进&#xff0c;共创辉煌。 在https://blog.csdn.net/A…

【CSS】元素居中总结-水平居中、垂直居中、水平垂直居中

【CSS】元素居中一、 水平居中1.行内元素水平居中&#xff08;1&#xff09;text-align2.块级元素水平居中2.1 margin&#xff08;1&#xff09;margin2.2布局&#xff08;1&#xff09;flex justify-content&#xff08;推荐&#xff09;&#xff08;2&#xff09; flexmargin…

张驰咨询:关于六西格玛,有一些常见的疑惑!

​ 很多想要学习六西格玛的学员&#xff0c;经常会有这些困惑&#xff1a; 以前没有接触过六西格玛&#xff0c;需要什么基础吗&#xff1f;自学还是培训&#xff1f;哪些行业会用到六西格玛呢&#xff1f;学习六西格玛对以后的工作有哪些帮助&#xff1f;如何选择六西格玛培…

STM32配置读取双路24位模数转换(24bit ADC)芯片CS1238数据

STM32配置读取双路24位模数转换&#xff08;24bit ADC&#xff09;芯片CS1238数据 CS1238是一款国产双路24位ADC芯片&#xff0c;与CS1238对应的单路24位ADC芯片是CS1237&#xff0c;功能上相当于HX711和TM7711的组合。其功能如下所示&#xff1a; 市面上的模块&#xff1a; …

股票买卖接口怎么来的?

现在股票买卖接口主要是在线上研发&#xff0c;有专业的开发团队进行源码开发和完善&#xff0c;但是&#xff0c;常常会在开发过程中出现问题&#xff0c;也就是遇到一些特殊的情况需要及时处理&#xff0c;那么股票买卖接口怎么开发实现出来的&#xff1f;一、股票买卖接口开…

案例分享| 助力数字化转型:广州期货交易所全栈信创项目管理平台上线

广州期货交易所项目管理平台基于易趋&#xff08;easytrack&#xff09;进行实施&#xff0c;通过近半年的开发及试运行&#xff0c;现已成功交付上线、推广使用&#xff0c;取得了良好的应用效果。1. 关于广州期货交易所&#xff08;以下简称广期所&#xff09;广期所于2021年…

MySQL8.0安装教程

文章目录1.官网下载MySQL2.下载完记住解压的地址&#xff08;一会用到&#xff09;3.进入刚刚解压的文件夹下&#xff0c;创建data和my.ini在根目录下创建一个txt文件&#xff0c;名字叫my&#xff0c;文件后缀为ini&#xff0c;之后复制下面这个代码放在my.ini文件下&#xff…

华为手表开发:WATCH 3 Pro(4)创建项目 + 首页新建按钮,修改初始文本

华为手表开发&#xff1a;WATCH 3 Pro&#xff08;4&#xff09;创建项目 首页新建按钮&#xff0c;修改初始文本初环境与设备创建项目创建项目入口配置项目认识目录结构修改首页初始文本文件名&#xff1a;index.hml新建按钮 “ 按钮 ”index.hml初 鸿蒙可穿戴开发 希望能写…

直播预告 | 对谈谷歌云 DORA 布道师:聊聊最关键的四个 DevOps 表现指标

本期分享 DORA 的全称是 DevOps Research and Assessment&#xff0c;是一个致力于 DevOps 调研与研究的组织&#xff0c;2018 年加入 Google Cloud。自 2014 年起&#xff0c;DORA 每年会发布一份行业报告&#xff0c;基于对数千名从业者的调研&#xff0c;分析高效能团队与低…

联想K14电脑开机全屏变成绿色无法使用怎么U盘重装系统?

联想K14电脑开机全屏变成绿色无法使用怎么U盘重装系统&#xff1f;最近有用户使用联想K14电脑的时候&#xff0c;开机后桌面就变成了绿色的背景显示&#xff0c;无法进行任何的操作。而且通过强制重启之后还是会出现这个问题&#xff0c;那么这个情况如何去进行系统重装呢&…

PMP证书要怎么考,含金量怎么样?

很多朋友在对PMP不是了解的时候&#xff0c;会有些犹豫&#xff0c;PMP证书到底值不值得考。考下来有用吗&#xff1f; PMP证书当然有用&#xff0c;要含金量有含金量&#xff0c;要专业知识有专业知识&#xff0c;不过要是考了不用&#xff0c;久而久之忘了学习的内容&#x…

怿星科技校招礼盒:我想开了

校招礼盒大揭秘为了帮助2023届新同学快速了解怿星文化增强认同感经过1个多月的精心准备我们的校招大礼盒终于跟大家见面啦&#xff01;&#xff01;我们用了大量的公司IP形象-小怿通过各式各样的姿势和表情欢迎新同学的到来搭配着IP的蓝色色调传递出一种科幻与探索的感觉希望加…