go指针的一个小坑

几乎可以肯定的说,go语言中除了闭包在引用外部变量的时候是传引用的,其他的时候都是传值的。如果你说形参可以定义为指针。好吧,那么告诉你这个指针的值其实是按照传值的方式使用的。

下面看个很浅显的例子:

func stillTest(v int) {
    v = v + 100
}
i := 100
fmt.Println("i ", i)
stillTest(i)
fmt.Println("after i ", i)

输出:

i  100
after i  100

两个值是不会有什么区别的。但是指针就会有什么区别么?

func anotherStillTest(v *int) {
    *v = *v + 100
}
fmt.Println("i ", i)
anotherStillTest(&i)
fmt.Println("after i ", i)

输出:

i  100
after i  200

你看到i的值改了,你大喊这难道不是传的引用吗。man,仔细看看下面的例子。

func addressStillTest(v *int) {
    x := 456
    v = &x
}
x := 1000
fmt.Println("x ", x)
addressStillTest(&x)
fmt.Println("after x ", x)

输出:

x  1000
after x  1000

是的,第一个方法中传了一个地址进去,但是我们明显不是对地址做的任何修改操作,而是做了一个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  5 6
Another Dog  5 6

对结构体直接做更换地址的操作还是不起作用。再一次表面函数的指针也是传值操作的。

如果要修改一个结构体呢?

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 ...

坑已填平!

时间: 2024-10-12 07:30:52

go指针的一个小坑的相关文章

CI load->view();的一个小坑。。。

CI load->view()  很智能,如果加载多个视图  他会全部读完再按顺序载入所有视图 但这里有一个小坑,底层会遍历你的函数,看有多少视图 再决定当前的视图是否为最后一个, 如果你的代码中有die exit这个的语句, 这个遍历就会被近中止, 所有的视图就都不会执行 切记 切记.. 如果想要中断这种机制,  直接执行视图,不执行下面的语句, : 加上$this->output->_display();就好了 但是这样就会失去灵活性. 谨慎用.

post到https的一个小坑

一个小坑,坑了我半天时间 本地用的是.net2.0,post按照正常的httpwebrequest方式写没有问题,但是发布到服务器上是.net4.0,于是开始报错“基础连接已关闭:发送时发生错误”. 做了几个修改,于是成功. 1.添加TLS 2.添加httpversion11 3.url改为IP地址(这个不确定有没有关系) post方法如下: ///zhhprivate string Post(string url, string json) { System.Net.HttpWebReques

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

go的变量声明有几种方式: 1 通过关键字 var 进行声明 例如:var i int   然后进行赋值操作 i = 5 2 最简单的,通过符号 := 进行声明和赋值 例如: i:=5 golang会默认它的类型 下面看一段代码,我们先声明一个变量a,然后再重新声明变量a,b,在这个函数中,变量a被声明了2次,成为a的重声明(redeclare),执行结果为23 package main import ( "fmt" ) func main(){ a:=1 a,b:=2,3 fmt.P

关于sniff函数的一个小坑

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

可能你不知道的字符串中的一个小坑!!!

简单的记录一个小问题,一直居然都没怎么注意,心底对自己深深的说了一句:"你真菜"! 平时日常我们接触到的数组去重太常见了.然后对于字符串的去重,也是可能用的IndexOf.或者转成数组去查重,然后再转换回来! 在尝试用其他方法的时候遇见一个小问题,在此记录下来与大家分析! var str = '521213756406'; for(var i = 0; i < str.length-1;i++){ for(var j = i+1;j < str.length; j++){

js变量提升的一个小坑

好久没写博客了,原本想实训结束能对整个实训项目认真总结一下,没想到回到学校一点都不轻松,最近在制作网页版简历,遇到了一个小问题,现在不总结以后肯定忙得顾不上,所以长话短说,抓紧时间写下来. 对js语法比较熟的同学可能都知道:js是没有块级作用域的,有一个新手很容易出错的地方 for(var i = 0 ; i < 10 ; i ++){ setTimeout(function(){ console.log(i) },1000*i) } 这段代码会输出10个10,而不是期望的1,2,...,10,

php当数据库update遇到并发,一个小坑

有一个答题的小项目,表的字段如下: id 用户id times 答题次数 questions 回答的问题id,这是一个php serialize()的字符串 当用户答完题像后端提交结果时,构建的post包如下: { 'id':1, 'questionid':38 } 后台逻辑如下: $user = User::findFirst("id = ?1",array('id'=>$_POST['id']));//取得用户模型 $questions = unserialize($user

c语言中指针的一个小错误

在定义指针后需要给指针赋值然后才能使用*p赋值或被赋值,这是个基础问题,没有理解,导致出问题. 空指针 ,也称悬 游指 针 ,是使 用 未初 始化 的指 针 .指针变量未初始化时它的值不是没有 ,而是一个不确定值 ,它 的指 向也 是 不确 定 的,可 能 会 破 坏 系 统 正 常工作状 态 ,出现灾难 性后果 .例 :m ain ( ){int a = 10 , *p a :*p a = a :*pa +=5 :prin tf (“a=%d ”, p a) :)本例中的程序本意是利用指 针将

[Unity热更新]ulua学习笔记01:一个小坑

看了一下以前写的文章,发现都好水啊..我也想写出能真正帮到别人的文章,但没办法啊,自己的脑子太笨了..希望可以通过不断学习,终有一天能写出点好文章! 最近在学习unity中的热更新,既然大神都说ulua效率最高(就现在来说),那就学习ulua吧!首先要下载的是ulua的包,现在的最新版本是1.08,而且根据官网上说的,网上流行的1.03/1.05含有大量的bug,所以我选择了最新的版本,谁知道就掉进了第一个坑! 因为是菜鸟,所以先复制一下网上的代码看看效果如何,结果碰到这样的错误: 搜索了这些错