前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >指针那么容易出错,为什么Go还保留?

指针那么容易出错,为什么Go还保留?

作者头像
小锟哥哥
发布2022-05-10 08:29:07
2870
发布2022-05-10 08:29:07
举报
文章被收录于专栏:GoLang全栈

如果你想知道为什么 Go 的运行效率会那么快?

为什么你的程序老是报 invalid memory address or nil pointer dereference?

那了解指针是一定少不了的!

什么是指针?

先干一张百度百科是怎么解释指针的图:

看完后感觉如何?

我记得我第一次听说指针是在接触 C++ 的时候,那简直是噩梦,太抽象了!

所以这篇文章我尽量写得通俗易懂点。

很庆幸的是,在后来发展起来的语言,比如 Java 基本就已经看不见他的身影了,因为指针太难了,非常反人类。

回到正题,什么是指针?

计算机最重要的两个硬件就是 CPU 和内存吧,CPU 负责计算,内存负责临时存储数据。

我们在写代码时,定义的变量在程序运行时,这些变量都被放在了内存里面,那内存是怎么存数据呢?

你可以粗暴的理解他就是一个记事本,如下图:

浅绿色的部分就可以理解是内存,里面各种颜色的块就是里面存的数据。

当然实际情况不可能这么规则,不同长度的数据,分配的块大小和长度都不一样。

查过字典的同学都能明白,当我们要查某个字的时候,会去目录里面看这个字在第几页,这个第几页就可以理解是这个字在这个字典里面的地址。

内存也是这样,我们在内存里面存放的任何数据都有一个地址,便于 CPU 去取数据。

存放这个地址的变量就是指针!

Go语言里面的指针

Go 里面并没完全抛弃指针,因为在很多时候有指针的存在,在效率上会高很多。

但是个人感觉 Go 对指针的处理非常恰到好处,先来看一段代码:

代码语言:javascript
复制
package main

import "fmt"

func main() {
 a := "hello"
 fmt.Println(a) //[1]
 fmt.Println(&a) //[2]
}

然后这是输出的结果:

代码语言:javascript
复制
hello
0xc000010230

标记了 [1] 的那行,是打印这个变量的值。

标记了 [2] 的那行,是打印这个变量的指针地址。

指针有什么用?

可以直接修改指向数据的值!

有时候我需要在一个方法里面修改传进来的变量值,比如下面这段代码:

代码语言:javascript
复制
func main() {
 a := "hello"
 fmt.Println(a)
 update(a)
 fmt.Println(a) //[1]
}

func update(in string)  {
 in = "word"
}

这段代码执行后的结果应该是这样的,直接输出两行 hello:

代码语言:javascript
复制
hello
hello

假如我现在想在 update 这个方法里面修改 a 这个变量的值,我想在当 [1] 的那段代码执行时,打印 word ,该怎么办?

此时就可以使用指针来处理,直接把 a 变量的地址传给方法,然后方法里面直接针对这个地址进行操作。

代码语言:javascript
复制
func main() {
 a := "hello"
 fmt.Println(a)
 update(&a)
 fmt.Println(a)
}

func update(in *string)  {
 *in = "word"
}

这里面关键点就是 *:

放在类型前面就是申明这是一个指针类型,放在变量前面就是通过这个指针取他值。

而在变量前面放 & 这个字符,就是取这个变量的指针。

到目前为止,Go 指针的核心知识点就这么多,剩下的都是围绕这些在开展。

空指针的坑

来看下这个代码:

代码语言:javascript
复制
var b *int
*b = 12

如果运行会怎么样?

他会报错!

代码语言:javascript
复制
panic: runtime error: invalid memory address or nil pointer dereference

我们要操作指针变量时,他必须是一个有指向的地址。

这段代码里面,变量 b 他声明了,但是内存里面并未分配内存地址给他,所以你此时去操作就会报空指针!

所以怎么处理呢?

初始化时就要求分配地址就好了,比如这样:

代码语言:javascript
复制
var b *int = new(int)

但是我们一般不这么写,会结合 Go 的类型自动推断来处理,如下:

代码语言:javascript
复制
b := new(int)

什么情况下使用指针?

在 Go 语言里面对指针是非常克制的,比如他不允许直接指针计算等。

那为什么还要考虑保留指针?

如果不用指针,在传值的时候,就只能采用拷贝的方式,所以在复杂或者大的数据传递时会比较消耗性能。

但是在使用时有几点需要注意的:

1、不要对 channel 这类引用类型使用指针

2、对int、bool这样小的数据没必要使用指针

3、如果需要并发安全,则尽可能的不要使用指针

4、指针最好不要嵌套,也就是一个指针指向另一个指针

如果你还有关于 Go 里面指针的疑惑,欢迎给我留言,一起讨论!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-09-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 GoLang全栈 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 什么是指针?
  • Go语言里面的指针
  • 指针有什么用?
  • 空指针的坑
  • 什么情况下使用指针?
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档