go slice获取唯一值_Go语言引用传递与值传递
先说结论
GO中只有值传递,没有引用传递
所谓值传递,就是实参通过拷贝将自身内容传递给形参。也就是将传递的内容拷贝一份,给函数。所以函数外和函数里对这个参数地址求值,应该是不一样的。
证明如下:
func main() {slice := []int{0,1,2,3}m := make(map[string]string)m["A"] = "a"var i *inta := 123i = &afmt.Printf("[main pointer] %pn", &i)fmt.Printf("[main map] %pn", &m)fmt.Printf("[main slice] %pn", &slice)get(slice, m, i)
}func get(s []int, m map[string]string, i *int) {fmt.Printf("[get pointer] %pn", &i)fmt.Printf("[get map] %pn", &m)fmt.Printf("[get slice] %pn", &s)
}// output
[main pointer] 0xc0000ae020
[main map] 0xc0000ae018
[main slice] 0xc0000a6020
[get pointer] 0xc0000ae038
[get map] 0xc0000ae030
[get slice] 0xc0000a6040
可以发现,slice、map、指针在传递过程中,地址都发生了变化。这说明传递的是一份拷贝。
但是我们又发现,在函数里修改slice、map,函数外的值也会改变,这是为什么呢?
// main
get(slice, m, i)
fmt.Println(slice)
fmt.Println(m)
fmt.Println(*i)// get
s[1] = 9999
m["A"] = "QQQQQ"
a := 999
i = &a// output
[0 9999 2 3] // 修改之前为 []int{0,1,2,3}
map[A:QQQQQ] // 修改之前为 m["A"] = "a"
123 // 修改之前为 *i = 123
这就必须说到slice、map的存储结构了。以slice为例
slice结构主要包括3个部分:data、len、cap。结构中的len和cap分别指示元素数量和容量。append使得len变大,但如果append之后的元素个数大于cap,会引发扩容机制。此时,会重新创建一个容量适合的底层数组。data为指针,指向底层数组。
所以slice本质上指的就是这个结构(data+len+cap,不包括底层的数组)。在参数传递过程中,这个结构拷贝了一份,data指向的还是原来的底层数组。当我们对slice中的元素进行修改时,还是会通过拷贝之后的data,直接对底层数组进行修改。
go 中,slice、map、channel都是引用类型,所以都会有如上的特性。
由于slice在扩容的过程中,会重新创建底层数组,data指向新的数组。那么,我们可以推测,在get函数中如果能触发扩容,那么修改新的底层数组,并不会对main中的slice造成影响。是否这样呢?
func main() {slice := []int{0,1,2,3}fmt.Printf("[main slice] %pn", &slice)get(slice)fmt.Printf("[new slice] %vn",slice)
}func get(s []int) {fmt.Printf("[get slice] %pn", &s)s = append(s, 9999)
}// output
[main slice] 0xc0000a6020
[get slice] 0xc0000a6040
[new slice] [0 1 2 3]
果然如此!那么就很清楚了。
总结
1、go中函数传递都是值传递
2、slice、map、channel都是引用类型,即便是值传递,结构内部还是指向原来的引用对象,所以函数体内可以直接修改元素。
3、如果slice触发扩容,data会指向新的底层数组,而不指向外部的底层数组了。所以之后再修改slice,不会对外部的slice造成影响。
go slice获取唯一值_Go语言引用传递与值传递相关推荐
- ostream作为函数返回值_GO语言基础函数
GO语言基础–函数 函数是组织好的.可重复使用的.用于执行指定任务的代码块.本文介绍了Go语言中函数的相关内容. 函数定义 Go语言中定义函数使用func关键字,具体格式如下: func 函数名(参数 ...
- jsonobject修改key的值_Go 语言 map 解析之 key 的定位核心流程
1 哈希表 哈希表属于编程中比较常见的数据结构之一,基本上所有的语言都会实现数组和哈希表这两种结构,Hash table 的历史是比较悠远的,我们在编程时也是离不开的,这种数据结构的作用其实很简单,就 ...
- 易语言取linux命令返回值,易语言取程序返回值写法
公告: 为响应国家净网行动,部分内容已经删除,感谢读者理解. 话题:易语言取程序返回值写法回答:在易语言中,程序包括"处理程序"都有六部分组成.一.程序名,就是程序的名称,程序名不 ...
- c语言编程实现表达式求值,c语言实现表达式求值的方法
c语言实现表达式求值的方法 发布时间:2020-06-22 16:45:46 来源:亿速云 阅读:82 作者:Leah 这期内容当中小编将会给大家带来有关c语言实现表达式求值的方法,以专业的角度为大家 ...
- python3 获取file大小_Go语言 | 你还在这样获取文件的大小吗?
在项目中,我们可能会需要获取一个文件的大小,在Golang(Go语言)中,有很多方法来获取一个文件的大小,看看你是否还在用最慢的方式. Read字节方式 第一种,是最直观会想到的,也就是打开文件,把文 ...
- mysql查询唯一单词_MySql从表中获取唯一单词列表,其中字段中的值用逗号分隔
我不确定这是否可以用纯SQL(MySQL),但无论如何我会问.我有这样一张桌子: ID TAGS ----------------------------- 1 word1,word2,word3 2 ...
- ostream作为函数返回值_Go语言入门必知教程-函数
函数是为了执行特定任务而存在于程序内的一组语句,函数接受输入并返回输出. 函数允许将常用的代码块提取出来成为单个组件. 使用最广的Go函数是main(),每个独立的Go程序都必须有个main函数. 创 ...
- 高精度计算PI值 C语言 思路,高精度计算PI值
高精度计算PI值 高精度计算PI值 所用公式: #include #include typedef struct list{ int data; struct list *next; struct l ...
- 关于值类型和引用 类型
-----------------------------------------关于值 类型 和 引用 类型--------------------------------------------- ...
最新文章
- C# NPOCO 轻量级ORM框架(进阶)
- 用go语言制作读取excel模板批量生成word工具
- C++ 反转单向链表
- 关于web性能一些特性汇总
- 边缘计算 | 阿里边缘云原生平台研发工程师招聘
- easyui前端实现多选框_EasyUI实现下拉框多选功能
- 为什么上一家公司离职?
- linux编译命令io,Hadoop 用命令行编译URLCat
- C语言练习题(递归)
- 如何从产品和技术角度上做一个好产品----软件公司如何开源节流(二)
- python中show函数的用法_python学习笔记之——函数模块
- GPS 入门 6 —— 各国卫星导航系统比较(北斗、伽利略、GLONASS、GPS)(转)
- excel高级功能-分级显示
- matlab 两个txt文件的合并。。
- javascript 获取当前日期 月份 时间
- 计算机硬件资源如何共享,如何设置计算机共享资源
- python queue 查询是否在队列中_Python queue队列
- STM32 SPI NSS大揭秘
- 【Effective C++ 条款03 笔记】尽可能使用const
- linux学习笔记2.0
热门文章
- Python3面向对象编程的三大特性 封装、继承、多态
- C++中转换构造函数:将其它类型转换为当前类的类型
- java facets_Java UIComponent.getFacets方法代码示例
- 如何提高3D点云目标检测的难例精度?
- web在线阅读日志文件,response.getOutputStream().write中文乱码原因
- RDKit toolkit实战二:Generating Similarity Maps Using Fingerprints
- 可视化生信分析利器 Galaxy 之 Docker 部署
- ESTL:新型多重扩增子测序法可实现污水中 SARS-CoV-2 RNA 的精确定量和病毒溯源...
- Nature子刊:南土所贾仲君组-稻田甲烷氧化的微生物机制
- cap3拼接sanger序列:在线+本地分析方法实战