几乎可以肯定的说,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指针的一个小坑的更多相关文章

  1. 注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式

    注意Android里TextView控件的一个小坑,用android:theme来设置样式时动态载入的layout会丢失该样式 这个坑,必须要注意呀, 比如在用ListView的时候,如果在List_ ...

  2. go的变量redeclare的问题,golang的一个小坑

    go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int   然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会 ...

  3. mysql url 连接配置的一个小坑。 工作中不会遇到。 学习的时候会

    <property name="driverClassName"> <value>com.mysql.jdbc.Driver</value> & ...

  4. 关于sniff函数的一个小坑

    最近在用scapy模块写一个关于WiFi的脚本时用到sniff函数,其中遇到了一个小坑,记录如下: sniff函数是在指定网卡上每次嗅探到一个数据包后然后将它传给prn指定的函数.

  5. Github作为图床的一个小坑

    Github作为图床的一个小坑 前言 听了少铭同学建议把github作为图床,结果遇到了一个小坑,总是显示不出来图片. 问题描述与解决 形如下的链接是显示不出来的: https://github.co ...

  6. Go的List操作上的一个小“坑”

    转自http://sharecore.net/blog/2014/01/09/the-trap-in-golang-list/ 一直想不清楚一个问题,简单设计的东西到底是“坑多”还是“坑少”呢? 复杂 ...

  7. [LeetCode]29 两数相除和一个小坑点

    给定两个整数,被除数 dividend 和除数 divisor.将两数相除,要求不使用乘法.除法和 mod 运算符. 返回被除数 dividend 除以除数 divisor 得到的商. 示例 1: 输 ...

  8. 小程序踩过的一个小坑---解析二维码decodeURIComponent() url解码

    因为我们需要用户扫码进入小程序,每一个货柜都有一个对应的二维码,当然每个二维码里的信息也不一样.用户扫码进入小程序之后,二维码的信息会以参数q带进去,而我们只能在onLoad事件中拿到这个参数, 但是 ...

  9. 关于js中 toFixed()的一个小坑

    作为一名前端,大家都应该知道,toFixed()的作用,toFixed()经常用于前台与后台数据格式的转换,套用下w3c上面的定义: 定义和用法toFixed(n) 方法可把 Number 四舍五入为 ...

随机推荐

  1. Mysql 获取当月和上个月第一天和最后一天的解决方案

    #获取当前日期select curdate(); #获取当月最后一天select last_day(curdate()): #获取本月的第一天select date_add(curdate(),int ...

  2. IOS6新特性之下拉刷新<UIRefreshControl>

    在IOS6未发布之前,几乎都是使用那个UIRefresh在实现下拉刷新,甚至有人还是先了上拉的功能,不得不说牛人很多啊.可能是Apple意识到了这个功能的实用性,在IOS6中增加了下拉刷新,但是上啦还 ...

  3. 简单AOP

    代码如下 //使用说明 //1,新加接口与类 //2,新加类并实现ICallHandler类: ExecuteHandler //3,新建特性并实现HandlerAttribute和重写其中的Crea ...

  4. 是否需要主动调用Bitmap的recycle方法

    一个Bitmap使用完后,是只需要等它成为垃圾后让GC去回收,还是应该主动调用recycle方法呢?或者说,主动调用recycle方法是否有好处,是否能马上回收内存呢? 带着这个问题来看源码(我看的4 ...

  5. 【Linux】svn环境配置

    Ubuntu 安装svn环境配置 1. 安装 sudo apt-get install subversion 安装过程需要数据[Y] 2. svn位置选择 安装完成之后,选择svn目录位置, 将其放在 ...

  6. hdoj1251-统计难题 【字典树】

    http://acm.hdu.edu.cn/showproblem.php?pid=1251 统计难题 Time Limit: 4000/2000 MS (Java/Others)    Memory ...

  7. Spring编程式事务管理

    --------------------siwuxie095                                 Spring 编程式事务管理         以转账为例         ...

  8. 根据二进制和十进制转换规则转换成游戏[xyytit]

    摘要: 二進位是由十進位轉換而成,它的數字都由1.0組成的.我們研究發現由十進位轉換而成的二進位的數字可以不只局限在於1~127,它的數可以更加深加廣,並且可以利用二進位的規則轉換成遊戲.我們利用2n ...

  9. PS切图导出代码后出现的图片布局散乱的解决方法——table布局

    前言: 一般来说,大部分美工PS切图后导出的都是使用PS默认的table布局的页面,出现最多的异常是上传代码,替换图片后,发现图片布局散乱,完全不是想要的效果.轻微的是浏览器不兼容,只有部分浏览器可以 ...

  10. win10下docker安装和配置镜像仓库

    初学docker记录一下流程 1.首先安装直接官网下载 DockerToolbox 即可,安装过程傻瓜式下一步即可.(这个集成了虚拟机,果然安装过的可以去掉) 2.安装好后双击Docker Quick ...