几乎可以肯定的说,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. 快快快!27个提升效率的iOS开源库推荐(转)

    CSDN移动将持续为您优选移动开发的精华内容,共同探讨移动开发的技术热点话题,涵盖移动应用.开发工具.移动游戏及引擎.智能硬件.物联网等方方面面.如果您想投稿.参与内容翻译工作,或寻求近匠报道,请发送 ...

  2. 进入一个docker容器

    Starting from Docker 1.3 you can use Docker exec to enter a Docker container : docker exec -it CONTA ...

  3. 判断一个对象是否为真 __nonzero__ 方法和 __len__方法

    class A(): def __nonzero__(self): # 判断 一个对象是否为空,先查看该方法的返回值 return 1 def __len__(self): # 如果没有上一个方法,那 ...

  4. 给定一个十进制数,将其转化为N进制数-----17年滴滴笔试题

    题目:给定一个十进制数M,将其转化为N进制数,其中2<=N<=16,其中N为32为整型数; 输入:M N,如7 2 输出转化结果:111 注意点:考虑负数的情况,记得添加负号(其实直接添加 ...

  5. js中的Event对象

    event代表事件的状态,例如触发event对象的元素,鼠标的位置及状态,按下的键等等 event对象只在事件发生的过程中才有效. <!DOCTYPE html><html lang ...

  6. Hibernate 中 联合主键映射 组合关系映射 大对象映射(或者说文本大对象,二进制数据大对象)

    Clob:文本大对象,最长4G Blob:二进制数据大对象,最长4G util: public class HibUtil { private static SessionFactory sessio ...

  7. Numpy数据存取

    Numpy数据存取 numpy提供了便捷的内部文件存取,将数据存为np专用的npy(二进制格式)或npz(压缩打包格式)格式 npy格式以二进制存储数据的,在二进制文件第一行以文本形式保存了数据的元信 ...

  8. Python 列表表达式 ,迭代器(2) Yield

    .yield 暂存为list def max_generator(numbers): current_max = for i in numbers: current_max = max(i, curr ...

  9. 大型运输行业实战_day02_1_数据库设计与powerDesigner使用

    1.安装powerDesigner 1. 傻瓜式的安装 2.在安装的过程中选择地区后才可以点击同意和下一步 3.安装地址,建议直接把c改为d 4.其他选项直接下一步 2.使用powerDesigner ...

  10. 关于使用service的上下文和activity来读取sharedpreferences的同步问题

    比如我用activity 对象 mainactivity 的context 获取了sharedpreferences对象,并putString(context, "demo", & ...