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 四舍五入为 ...
随机推荐
- DateFormat工具类
import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java. ...
- MonoDevelop 设置
菜单:Tools->Options Text Editor Behavior Automatic behaviors × enable on the fly code formatting Sy ...
- 组队打代码 !!! ——Alpha项目冲刺
Alpha阶段 - 博客链接合集 队伍名称: 代码那些事儿 学号 姓名 211606320 刘佳 211606313 李佳 211606303 陈水莲 211606302 曾丽丽 211606338 ...
- 通过Roslyn构建自己的C#脚本(更新版)(转)
http://www.cnblogs.com/TianFang/p/6939723.html 之前写过文章介绍过如何通过Roslyn构建自己的C#脚本,但那篇文章是参考自Roslyn CTP版 ...
- 1Java语言概述——重拾Java
1.1 Java 语言诞生 Java 是1995 年 由 Sun公司开发的革命性编程语言. 1.2 Java 的特点 序号 主题 描述 1 简单 比C++简单 2 面向对象 基于对象的编程更符合人的思 ...
- clusterProfiler包
1)enrichGO:(GO富集分析) 描述:GO Enrichment Analysis of a gene set. Given a vector of genes, this function ...
- Nexus 安装 使用说明
1 . 私服简介 私服是架设在局域网的一种特殊的远程仓库,目的是代理远程仓库及部署第三方构件.有了私服之后,当 Maven 需要下载构件时,直接请求私服,私服上存在则下载到本地仓库:否则,私服请求外部 ...
- go语言中通过http访问需要认证的api
func main() { //生成client 参数为默认 client := &http.Client{} //生成要访问的url url := "https://api.XXX ...
- Windows下Fortran编译Lapack库及使用的方法(转自新浪)
Lapack 是一套被非常广泛使用的线性代数计算工具库,现在的主要编写语言时 Fortran90 .Lapack 基本上可以说是速度最快的线性代数计算库,我们看看官方给出的其被应用的几个地方就可以看出 ...
- Codeforces Beta Round #14 (Div. 2)
Codeforces Beta Round #14 (Div. 2) http://codeforces.com/contest/14 A 找最大最小的行列值即可 #include<bits/s ...