利志分享
fast_forward
view_headline
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
开发工具箱
go教程
clickhouse教程
kafka教程
python教程
shell教程
原创杂文
打赏
go基础知识
go的环境搭建
go变量
go常量
go字符串
go数组和切片
go的map和range的使用
go的struct的使用
go的函数使用
go的interface的使用
go channel使用
go的routine使用
go的panic和recover使用
go实现http请求
go 复杂的http请求
go实现表单提交
go实现表单验证
go上传附件
go实现mysql连接
go实现redis操作
go对xml操作
go的json操作
go的base64使用
go实现websocket功能
go的单元测试
go的文件操作
go的web服务基础
golang url解析和包介绍使用
go的正则表达式-MatchString,FindString等的使用
golang实现从byte和文件中读取csv格式数据
go进阶
go的类型转换
go的map的多维应用
go的多维数组和slice使用
go的select使用
go的原子性atomic类库使用
go给图片添加水印
go给图片添加文字
go实现http的rpc服务
go实现tcp的rpc服务
go实现json格式的rpc服务
多个defer的执行问题
golang的队列机制实现同步主线程接受子协程的结果
go的值传递和引用传递以及引用类型的问题
go中的make和new的使用问题
golang读文件分析1
golang读文件分析2
golang实现自然周计算
golang实现读写excel
go实战
beego的安装和使用
beego聊天室的基本配置
beego聊天室的生成
Go 写一个类似 cron 的定时任务管理器
Go 调度器 M, P 和 G
AES对称加密算法如何用golang语言实现?
非对称加密的RSA算法如何通过golang来实现?
golang实现http2.0服务端,客户端完整案例
go实战总结
go的日期操作类使用-日常使用类库no.1
go的字符串的连接讲解-日常实战总结no.1
golang实现队列服务-日常实战总结no.2
深入理解golang的channel的使用-日常实战总结no.3
go的sync.pool在实际应用中的讲解和性能分析比较-日常实战总结no.4
go语言中一个典型的引用类型的数据使用案例的注意点-日常实战总结no.5
go的sync包的使用详解1-日常实战总结6
go的sync包的使用详解2-日常实战总结7
深度学习go判断各个类型相等-日常实战总结8
go的排序类使用讲解-日常实战总结9
go的context使用讲解
golang 网络爬虫框架gocolly
golang实现桶排序
golang处理gb2312转utf-8编码的问题
golang实现单链的添加,删除以及翻转
golang的一个err不判断引起的血案(json.Marshal的error到底要不要判断?)
如何控制golang协程的并发数量问题-panic: too many concurrent operations on a single file or socket (max 1048575)
你所要知道的redis客户端返回值知识点
golang实现连续的时间,比如连续的天,月,年等。
go深入
由引用类型引发的概念的深入理解
sync.WaitGroup深入源码理解
golang如何创建动态的struct类型以及如何转换成slice类型
深入理解go的管道数据读写
关于go的只读管道只写管道以及单向管道的理解
深入理解go的slice深入,slice扩容机制
深入理解go的函数参数传递
golang实现动态调用不同struct中不同的方法
如何配置sqlx.DB的SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime来保证更好的性能
深入理解go的select原理
深入理解golang的GPM模型
精通golang的项目管理go modules
深入理解golang的GC回收机制
超级肝文-深入剖析客户端出现connect reset by peer报错相关的技术知识
Golang源码深入-Go1.15.6发起http请求流程-1
Golang源码深入-Go1.15.6发起http请求流程-2
Golang源码深入-Go1.15.6发起http请求流程-3(http2)
go应用
需求整理-手把手带大家用go开发一个匿名在线聊天室
第二篇-手把手带大家用go开发一个匿名在线聊天室
第三篇-手把手带大家用go开发一个匿名在线聊天室
go面试
【建议收藏】吐血整理Golang面试干货21问-吊打面试官-1
【建议收藏】整理Golang面试第二篇干货13问
【建议收藏】Redis知识干货汇总
【建议收藏】Mysql知识干货(mysql八股文)汇总
目录
go基础知识
go的环境搭建
go变量
go常量
go字符串
go数组和切片
go的map和range的使用
go的struct的使用
go的函数使用
go的interface的使用
go channel使用
go的routine使用
go的panic和recover使用
go实现http请求
go 复杂的http请求
go实现表单提交
go实现表单验证
go上传附件
go实现mysql连接
go实现redis操作
go对xml操作
go的json操作
go的base64使用
go实现websocket功能
go的单元测试
go的文件操作
go的web服务基础
golang url解析和包介绍使用
go的正则表达式-MatchString,FindString等的使用
golang实现从byte和文件中读取csv格式数据
go进阶
go的类型转换
go的map的多维应用
go的多维数组和slice使用
go的select使用
go的原子性atomic类库使用
go给图片添加水印
go给图片添加文字
go实现http的rpc服务
go实现tcp的rpc服务
go实现json格式的rpc服务
多个defer的执行问题
golang的队列机制实现同步主线程接受子协程的结果
go的值传递和引用传递以及引用类型的问题
go中的make和new的使用问题
golang读文件分析1
golang读文件分析2
golang实现自然周计算
golang实现读写excel
go实战
beego的安装和使用
beego聊天室的基本配置
beego聊天室的生成
Go 写一个类似 cron 的定时任务管理器
Go 调度器 M, P 和 G
AES对称加密算法如何用golang语言实现?
非对称加密的RSA算法如何通过golang来实现?
golang实现http2.0服务端,客户端完整案例
go实战总结
go的日期操作类使用-日常使用类库no.1
go的字符串的连接讲解-日常实战总结no.1
golang实现队列服务-日常实战总结no.2
深入理解golang的channel的使用-日常实战总结no.3
go的sync.pool在实际应用中的讲解和性能分析比较-日常实战总结no.4
go语言中一个典型的引用类型的数据使用案例的注意点-日常实战总结no.5
go的sync包的使用详解1-日常实战总结6
go的sync包的使用详解2-日常实战总结7
深度学习go判断各个类型相等-日常实战总结8
go的排序类使用讲解-日常实战总结9
go的context使用讲解
golang 网络爬虫框架gocolly
golang实现桶排序
golang处理gb2312转utf-8编码的问题
golang实现单链的添加,删除以及翻转
golang的一个err不判断引起的血案(json.Marshal的error到底要不要判断?)
如何控制golang协程的并发数量问题-panic: too many concurrent operations on a single file or socket (max 1048575)
你所要知道的redis客户端返回值知识点
golang实现连续的时间,比如连续的天,月,年等。
go深入
由引用类型引发的概念的深入理解
sync.WaitGroup深入源码理解
golang如何创建动态的struct类型以及如何转换成slice类型
深入理解go的管道数据读写
关于go的只读管道只写管道以及单向管道的理解
深入理解go的slice深入,slice扩容机制
深入理解go的函数参数传递
golang实现动态调用不同struct中不同的方法
如何配置sqlx.DB的SetMaxOpenConns SetMaxIdleConns 和 SetConnMaxLifetime来保证更好的性能
深入理解go的select原理
深入理解golang的GPM模型
精通golang的项目管理go modules
深入理解golang的GC回收机制
超级肝文-深入剖析客户端出现connect reset by peer报错相关的技术知识
Golang源码深入-Go1.15.6发起http请求流程-1
Golang源码深入-Go1.15.6发起http请求流程-2
Golang源码深入-Go1.15.6发起http请求流程-3(http2)
go应用
需求整理-手把手带大家用go开发一个匿名在线聊天室
第二篇-手把手带大家用go开发一个匿名在线聊天室
第三篇-手把手带大家用go开发一个匿名在线聊天室
go面试
【建议收藏】吐血整理Golang面试干货21问-吊打面试官-1
【建议收藏】整理Golang面试第二篇干货13问
【建议收藏】Redis知识干货汇总
【建议收藏】Mysql知识干货(mysql八股文)汇总
深入理解go的函数参数传递
阅读:581
分享次数:0
首先我们要有一个理解:go的函数参数传递都是值传递,为什么说是传值呢?因为go的函数传递都是复制了一份传递到参数中。下面我们看一个例子: package main import "fmt" func main() { a := 1 b := "xx" c := []int{1} d := map[string]string{"xx": "xxx"} e := Tmp{ Name: "xxx", } f := func() string { return "xxx" } g := new(Tmp) fmt.Printf("原来的:a:%p b:%p c:%p d:%p e:%p f:%p g:%p\n", &a, &b, &c, &d, &e, &f, &g) testParamFunc(a, b, c, d, e, f, g) } func testParamFunc(a int, b string, c []int, d map[string]string, e Tmp, f func() string, g *Tmp) { fmt.Printf("函数内的:a:%p b:%p c:%p d:%p e:%p f:%p g:%p\n", &a, &b, &c, &d, &e, &f, &g) } type Tmp struct { Name string } 执行结果如下: 原来的:a:0xc00000a0b0 b:0xc00003c1f0 c:0xc000004480 d:0xc000006028 e:0xc00003c200 f:0xc000006030 g:0xc000006038 函数内的:a:0xc00000a0e0 b:0xc00003c220 c:0xc0000044c0 d:0xc000006048 e:0xc00003c230 f:0xc000006050 g:0xc000006058 上面的例子我们看到了不管是什么类型传过来,函数都给复制了一份传递到函数中,函数的参数地址都变化了,参数地址指向的内容是原来的值。 **所谓值传递:指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。但是其实go里面有些类型会影响到实际参数,下面我们对不同的类型来不同的讲解。** ------------ 关于字符串和整形的参数传递例子: package main import "fmt" func main() { a := 1 bTmp := 2 b := &bTmp c := "xx" dTmp := "kk" d := &dTmp e := 3 fmt.Printf("a:%d b:%d c:%s d:%s e:%d\n", a, *b, c, *d, e) testFunc(a, b, c, d, &e) fmt.Printf("a:%d b:%d c:%s d:%s e:%d\n", a, *b, c, *d, e) } func testFunc(a int, b *int, c string, d *string, eParam *int) { a = 11 tmpInt := 22 b = &tmpInt c = "qqq" tmpStr := "ooo" d = &tmpStr *eParam = 33 } 执行结果如下: a:1 b:2 c:xx d:kk e:3 a:1 b:2 c:xx d:kk e:33 **字符串和整形传递函数里面是无法修改实参的,但是为什么e我们看那个值变化了呢?*eParam = 33这行代码其实不是对e直接赋值,是对eParam的地址进行重新赋值了,本来eParam传过来就是上面变量e的地址,然后在函数里面取*eParam就是变量e。** ------------ 关于struct参数传递 package main import "fmt" func main() { a := Tmp{ Name: "xxx", } b := &Tmp{ Name: "xxx", } fmt.Printf("a:%v b:%v\n", a, *b) testFunc2(a, b) fmt.Printf("a:%v b:%v\n", a, *b) } func testFunc2(a Tmp, b *Tmp) { a.Name = "ddd" b.Name = "ggg" } type Tmp struct { Name string } 执行结果如下: a:{xxx} b:{xxx} a:{xxx} b:{ggg} **struct的参数传递,如果是本身传递,参数内无法修改实参,但是如果是传struct地址,通过地址也能取参数的属性,这样是可以修改实参,所以我们看到b被修改了。** ------------ 关于slice,map,chan三种数据结构,我们也看下例子 package main import "fmt" func main() { a := []int{1, 2, 3, 6} b := []int{1, 2, 3, 6} c := map[string]string{"xxx": "vvv"} d := make(chan int, 1) fmt.Printf("a:%v b:%v c:%v d:%d\n", a, b, c, len(d)) testFunc3(a, b, c, d) fmt.Printf("a:%v b:%v c:%v d:%d\n", a, b, c, len(d)) } func testFunc3(a, b []int, c map[string]string, d chan int) { a = append(a, 100) b[3] = 100 c["iiii"] = "sss" d <- 1 } 结果如下: a:[1 2 3 6] b:[1 2 3 6] c:map[xxx:vvv] d:0 a:[1 2 3 6] b:[1 2 3 100] c:map[iiii:sss xxx:vvv] d:1 **结果是不是没想到呢?a通过append是没法直接修改实参,但是b呢通过直接操作某一个属性是可以修改的。因为a是slice,用append的话,slice会扩容,会copy一个slice,原来的地址(即临时参数)会指向新的slice,但是这个临时参数又和原来的传进来的变量地址不一样,所以没法修改实参。但是b呢,能修改是因为makeslice返回的是一个指针,我们通过修改属性其实修改的是b变量的指向底层数组指针属性,所以能修改。但是c呢,为什么直接传过来就直接修改了呢?这个得看看源码了,翻了一下makemap看看,makemap返回值是返回一个指针,其实就是map的地址,我们在函数内操作直接就修改了实参。关于d呢,原因和c是一样的,makechan会返回一个指针,函数内操作其实就是直接对传过来的变量的属性进行更改了,所以函数内操作直接修改了实参。** ------------ 下面我们过一下这个创建的函数的源码,以上的实例分析希望对大家有帮助,有问题随时交流。 创建slice func makeslice(et *_type, len, cap int) unsafe.Pointer { ...... return mallocgc(mem, et, true) } 创建map func makemap(t *maptype, hint int, h *hmap) *hmap { ...... return h } 创建chan func makechan(t *chantype, size int) *hchan { ...... return c }
感觉本站内容不错,读后有收获?
attach_money
我要小额打赏,鼓励作者写出更好的教程
扫码关注公众号:talk_lizhi