go指针的一个小坑
几乎可以肯定的说,go语言中除了闭包在引用外部变量的时候是传引用的,其他的时候都是传值的。如果你说形参可以定义为指针。好吧,那么告诉你这个指针的值其实是按照传值的方式使用的。
下面看个很浅显的例子:
func stillTest(v int) {
v = v +
}
i :=
fmt.Println("i ", i)
stillTest(i)
fmt.Println("after i ", i)
输出:
i
after i
两个值是不会有什么区别的。但是指针就会有什么区别么?
func anotherStillTest(v *int) {
*v = *v +
}
fmt.Println("i ", i)
anotherStillTest(&i)
fmt.Println("after i ", i)
输出:
i
after i
你看到i的值改了,你大喊这难道不是传的引用吗。man,仔细看看下面的例子。
func addressStillTest(v *int) {
x :=
v = &x
}
x :=
fmt.Println("x ", x)
addressStillTest(&x)
fmt.Println("after x ", x)
输出:
x
after x
是的,第一个方法中传了一个地址进去,但是我们明显不是对地址做的任何修改操作,而是做了一个dereference操作。然后修改了变量的值。而在上面的这个例子中才是对地址的操作。我们在函数addressStillTest中试图修改x指向的地址,由于x的地址是传值操作的,也就是拷贝过来的,所以修改是无效的。最后的输出结果也说明了这一点。
所以在函数操作方面,任何的参数都是按照传值操作的方式执行的。不管是穿的指针还是一般的一个值都是传值使用的。
下面再看看这个结构体的例子。首先需要有这个:
type Dog struct {
Name string
Type string
}
func addressTest(d *Dog) {
a := &Dog{"another cute dog", "another type"}
d = a
}
输出:
Dog
Another Dog
对结构体直接做更换地址的操作还是不起作用。再一次表面函数的指针也是传值操作的。
如果要修改一个结构体呢?
func anotherTest(d *Dog) {
a := &Dog{"another cute dog", "another type"}
d.Name = a.Name
d.Type = a.Type
}
输出:
Dog cute dog ...
Another Dog another cute dog another type
最后说明一个问题。在c,c++里如果从函数内部返回一个局部变量的指针的话是不对的。但是在Go里是可以的。Go的编译器会检查函数的局部变量指针是否会作为返回值给外部使用,如果是的话则将这个变量放在heap上延长其生命周期。
func test() *Dog {
return &Dog{"cute dog", "..."}
}
d := test()
fmt.Println("Dog ", d.Name, d.Type)
输出:
Dog cute dog ...
坑已填平!
补充
坑其实只是勉强的算是填平了。比如,我现在需要在一个方法中修改一个结构体实例的值。
type Person struct {
Name string
Phone string
} func main() {
session, err := mgo.Dial("server1.example.com,server2.example.com")
if err != nil {
panic(err)
}
defer session.Close() // Optional. Switch the session to a monotonic behavior.
session.SetMode(mgo.Monotonic, true) c := session.DB("test").C("people")
err = c.Insert(&Person{"Ale", "+55 53 8116 9639"},
&Person{"Cla", "+55 53 8402 8510"})
if err != nil {
log.Fatal(err)
} result := Person{}
err = c.Find(bson.M{"name": "Ale"}).One(&result)
if err != nil {
log.Fatal(err)
} fmt.Println("Phone:", result.Phone)
}
比如上例中,我需要从mongodb中取出结构体实例result的具体值,把一个指针传进,然后用给这个实例的每个成员分别赋值的方式可以得到数据库搜出来的具体的值。但是,如果我们一定要用指针替换的方式来取得这样的值该怎么办呢?
还是沿用最开始的例子里的type Dog struct结构体来定义测试方法:
func anotherAddressTest(d **Dog) {
a := &Dog{"address dog", "address dog type"}
*d = a
}
// get address out of a func
var aad = &Dog{"", ""}
fmt.Println("Dog ", aad.Name, aad.Type)
anotherAddressTest(&aad)
fmt.Println("Address Dog ", aad.Name, aad.Type)
输出:
Dog
Address Dog address dog address dog type
可以看到,值被修改了。整个的东西其实在原理上来说都是一样的,作为函数的参数直接拷贝过来的指针如果被修改了是不会传回去任何的东西的。但是,如果指针所指向的内容被修改了,可以带到函数的外部。所以,这里使用了指向指针的指针,也就是二级指针。根据上面得出的院里二级指针作为参数如果被修改了不会带出道函数的外部,但是整个二级指针指向的内容如果修改了却可以带导函数的外部。
这些都是很浅显的东西,平时日日重复的代码生活过得居然都疏忽了。与诸君共勉吧,stay hungry,stay foolish!
go指针的一个小坑的更多相关文章
- 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式
注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...
- go的变量redeclare的问题,golang的一个小坑
go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int 然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...
- mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会
<property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...
- 关于sniff函数的一个小坑
最近在用scapy模块写一个关于WiFi的脚本时用到sniff函数,其中遇到了一个小坑,记录如下: sniff函数是在指定网卡上每次嗅探到一个数据包后然后将它传给prn指定的函数.
- Github作为图床的一个小坑
Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...
- Go的List操作上的一个小“坑”
转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/ 一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂 ...
- [LeetCode]29 两数相除和一个小坑点
给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...
- 小程序踩过的一个小坑---解析二维码decodeURIComponent() url解码
因为我们需要用户扫码进入小程序,每一个货柜都有一个对应的二维码,当然每个二维码里的信息也不一样.用户扫码进入小程序之后,二维码的信息会以参数q带进去,而我们只能在onLoad事件中拿到这个参数, 但是 ...
- 关于js中 toFixed()的一个小坑
作为一名前端,大家都应该知道,toFixed()的作用,toFixed()经常用于前台与后台数据格式的转换,套用下w3c上面的定义: 定义和用法toFixed(n) 方法可把 Number 四舍五入为 ...
随机推荐
- linux基础命令:
linux基础命令: 显示 echo 输出我写的内容 ls 查看当前目录的文件 pwd 查看当前目录 ifconfig 查看网卡信息 grep 过滤 -v 取反 -n man 查看命令的帮助信息 md ...
- Java可重入锁与不可重入锁
可重入锁,指的是以线程为单位,当一个线程获取对象锁之后,这个线程可以再次获取本对象上的锁,而其他的线程是不可以的. synchronized 和 ReentrantLock 都是可重入锁. 可重入 ...
- 兼容当前五大浏览器的渐变颜色背景gradient的写法
<style type="text/css" media="screen"> #gradient { width: 200px; height: 2 ...
- maven package install deploy
1.maven package:打包到本项目,一般是在项目target目录下. 如果a项目依赖于b项目,打包b项目时,只会打包到b项目下target下,编译a项目时就会报错,因为找不到所依赖的b项目, ...
- 全国省市区数据库SQL(有可能不是最新的)
百度云下载地址:https://pan.baidu.com/s/1lStN7tYpwOtpC-r3G2X2sw
- Python并发讨论
手段有多线程,多进程,协程. 对于多线程: 由于GIL(全局解释器锁)的存在,多线程实际是单线程的,不能发挥多核的作用: 但对于IO密集型程序,多线程对于效率是有提高的,由于阻塞时,可能会切换到别的线 ...
- ios 8 联系人ABPeoplePickerNavigationController
一. ios 联系人ABPeoplePickerNavigationControllerDelegate方法,新添加下面两个联系人选中方法,适配iOS8需要实现 // Called after a p ...
- Volley的使用
Volley加载图片到控件上 VolleyUtils.getLoader(getContext()).get(zixun.getPicurl(), ImageLoader.getImageListen ...
- 【D3D】Direct3D中LPRECT(上左右底)和LPoint(x,y)之前转换
D3DSprite.cpp void CD3DSprite::DrawText(CD3DFont *pFont, char *szString, RECT &DesRect, D3DCOLOR ...
- 201621123008 《Java程序设计》第五周学习总结
1. 本周学习总结 1.1 写出你认为本周学习中比较重要的知识点关键词 关键词:接口,内部类. 1.2 尝试使用思维导图将这些关键词组织起来.注:思维导图一般不需要出现过多的字. 1.3 可选:使用常 ...