几乎可以肯定的说,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 数据备份及数据迁移

    一.使用mysql数据导出进行备份时,会备份整个表的数据,有时候只想备份一部分数据,这个时候可以使用如下方法: 1. 使用insert into 和 select结合: insert into tal ...

  2. unity 设置屏幕旋转

    只允许竖屏: Portrait                    √ Portrait Upside Down √ Landscape Right        × Landscape Left ...

  3. TEXT 15 A text a day...

    TEXT 15 A text a day... Mar 24th 2006 From The Economist print edition The medical uses of mobile ph ...

  4. static静态局部变量初始化问题

    第一次写博客之类的东西,主要是为了记录自己的学习过程,以便于记忆的加深和与各位大神进行探讨,学习更多的东西. 本次上传主要是关于静态局部变量的初始化问题. 首先,静态局部变量和全局变量一样,数据都存放 ...

  5. scala -- 柯里化

    柯里化 柯里化是把接受多个参数的函数,变成接受一个单一参数的函数.并且返回接受剩余参数和返回结果的新函数. 就是一个逐次消元的过程. 当把函数的元全消掉,就得到了值. 值就是零元函数. 二元函数 f( ...

  6. SPARK数据类型

    转自: http://www.cnblogs.com/tuitui1989/p/5331113.html 一.本地向量 有如下几个类: Vector(基类),DenseVector,SparseVec ...

  7. 贝叶斯vs频率派:武功到底哪家强?| 说人话的统计学·协和八(转)

    回我们初次见识了统计学理论中的“独孤九剑”——贝叶斯统计学(戳这里回顾),它的起源便是大名鼎鼎的贝叶斯定理. 整个贝叶斯统计学的精髓可以用贝叶斯定理这一条式子来概括: 我们做数据分析,绝大多数情况下希 ...

  8. Concurrency and Race Conditions

    1.当多个线程访问共享硬件或软件资源的任何时候,由于线程之间可能产生对资源的不一致观察,所以必须显式管理对资源的访问. 2.内核中的并发管理设施: (1). 信号量: P操作将信号量的值减 1 ,判断 ...

  9. 安装Anaconda以及jupyter的使用

    1)下载https://www.anaconda.com/download/ 2)安装 3)终端查看(Anaconda Prompt) 4)升级所有的包 初次安装下的软件包版本一般都比较老旧,因此提前 ...

  10. FP真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IN_SALES_ORDER数据不带CZ

    错误描述:真验货客户的成品和半成品编码部分没有带尾续,导致FP规划错误 IT角度: IN_SALES_ORDER数据不带CZ 现时前台页面数据: 现时后台数据: 一.跟进情况 1.执行SAP_SALE ...