什么是指针

指针是存储一个变量的内存地址的变量。

在上图中,变量 b 的值是 156,存储在地址为 0x1040a124 的内存中。变量 a 存储了变量 b 的地址。现在可以说 a 指向 b

指针的声明

指向类型 T 的指针用 *T 表示。

让我们写一些代码。

package main

import (
"fmt"
) func main() {
b := 255
var a *int = &b
fmt.Printf("Type of a is %T\n", a)
fmt.Println("address of b is", a)
}

& 操作符用来获取一个变量的地址。在上面的程序中,第 9 行我们将 b 的地址赋给 aa 的类型为 *int)。现在我们说 a 指向了 b。当我们打印 a 的值时,b 的地址将会被打印出来。程序的输出为:

Type of a is *int

address of b is 0x1040a124

你可能得到的是一个不同的 b 的地址,因为 b 可以在内存中的任何地方。

指针的空值

指针的空值为 nil 。

package main

import (
"fmt"
) func main() {
a := 25
var b *int
if b == nil {
fmt.Println("b is", b)
b = &a
fmt.Println("b after initialization is", b)
}
}

在上面的程序中,b 的初始值为 nil。接着将 a 的地址赋值给 b。程序的输出为:

b is <nil>
b after initialisation is 0x1040a124

指针解引用

解引用指针的意思是通过指针访问被指向的值。指针 a 的解引用表示为:*a

让我们通过一个程序看一下它是怎么工作的。

package main
import (
"fmt"
) func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a)
}

上面程序的第10行,我们将 a 解引用并打印这个解引用得到的值。和我们预期的一样,程序打印的是 b 的值。程序的输出为:

address of b is 0x1040a124
value of b is 255

让我们再写一个程序,该程序使用指针改变 b 的值。

package main

import (
"fmt"
) func main() {
b := 255
a := &b
fmt.Println("address of b is", a)
fmt.Println("value of b is", *a)
*a++
fmt.Println("new value of b is", b)
}

在上面的程序中,我们将 a 指向的值自增 1,这样做也改变了 b 的值,因为 a 指向 b。因此 b 的值变为 256。程序的输出为:

address of b is 0x1040a124
value of b is 255
new value of b is 256

传递指针给函数

package main

import (
"fmt"
) func change(val *int) {
*val = 55
}
func main() {
a := 58
fmt.Println("value of a before function call is",a)
b := &a
change(b)
fmt.Println("value of a after function call is", a)
}

在上面的程序中,第 14 行,我们将指向 a 的指针 b 传递给函数 change。在函数 change 内部,第 8 行,通过解引用修改了 a 的值。程序的输出如下:

value of a before function call is 58
value of a after function call is 55

不要传递指向数组的指针给函数,而是使用切片

假设我们需要通过函数修改一个数组。一个办法是将数组的指针作为参数传递给函数。

package main

import (
"fmt"
) func modify(arr *[3]int) {
(*arr)[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(&a)
fmt.Println(a)
}

在上面的程序中,第13行,数组 a 的地址传递给了函数 modify。在第8行的 modify 函数中,我们通过解引用的方式将数组的第一个元素赋值为 90。程序输出为:[90 90 91]

a[x] 是 (*a)[x] 的简写,因此上面的程序中,(*arr)[0] 可以替换为 arr[0]。让我们用这种简写方式重写上面的程序:

package main

import (
"fmt"
) func modify(arr *[3]int) {
arr[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(&a)
fmt.Println(a)
}

程序的输出依然是:[90 90 91]

虽然可以通过传递数组指针给函数的方式来修改原始数组的值,但这在 Go 中不是惯用的方式,我们可以使用切片完成同样的事情。

让我们用切片的方式重写上面的程序:

package main

import (
"fmt"
) func modify(sls []int) {
sls[0] = 90
} func main() {
a := [3]int{89, 90, 91}
modify(a[:])
fmt.Println(a)
}

在上面的程序中,第13行,我们传递了一个切片给 modify 函数。在函数内部,切片的第一个元素被修改为 90。程序的输出为:[90 90 91]。所以请不要以数组指针作为参数传递给函数,而是使用切片:)。这样的代码更加简洁,在 Go 中更常被使用。

Go 不支持指针运算

Go 不支持其他语言(比如C)中的指针运算。

package main

func main() {
b := [...]int{109, 110, 111}
p := &b
p++
}

上面的程序将报错:main.go:6: invalid operation: p++ (non-numeric type *[3]int)


												

go里面的指针用法的更多相关文章

  1. Leetcode刷题之矩阵中的指针用法

    矩阵中的指针用法 1 快慢指针 ​ Leetcode27移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度.不要使用额外的数组 ...

  2. C# this指针用法

    this指针是什么: 这里有一些面向对象编程的概念需要说明:类(Class)的概念和对象(Object)的概念类是对事物概括,也是C#编码时所有代码归属的基本单位:而对象是对类的实例化,也就是C#里n ...

  3. c++ 智能指针用法详解

    本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被c++11弃用. 为什么要使用智能 ...

  4. C和C指针小记(九)-指针用法1

    1. *p++ 最常用的一个指针的用法,就是在循环中用来迭代. *p++ 共有3步操作: 1.++操作符把p所指向的内存中的值复制一份 2.++操作符把p加1(实际是一个p所指内存单元的大小,这也是编 ...

  5. typedef函数指针用法

    typedef void(*vp)(); 将vp声明为一个函数指针类型,该类型的指可以针指向一个没有参数,带空返回值的函数. 调用方法vp p;创建一个vp类型的函数指针p void print(vp ...

  6. c语言指针用法

    一.指针 int t 定义整型变量 int *p p为指向整型数据的指针变量 int a[n] 定义整型数组a,它有n个元素 int *p[n] 定义指针数组p,它由n个指向整形数据的指针元素组成 i ...

  7. C++中const指针用法汇总

    这里以int类型为例,进行说明,在C++中const是类型修饰符: int a; 定义一个普通的int类型变量a,可对此变量的值进行修改. const int a = 3;与 int const a ...

  8. C语言的指针用法:输入一堆字符,把非字母的删去。

    char *p,a[20]; int i; gets(a);    //这个语句不同于getchar(),后者只能一次输入一个,而前者可以一次输完所有的字符!!! p=a;        //这个语句 ...

  9. C语言之指针用法总结

    C语言指针概述:1.计算机系统中,无论是存入或是取出数据都需要与内存单元打交道,物理器件通过地址编码寻找内存单元.2.地址编码是一种数据,C语言的指针类型正是为了表示这种计算机所特有的地址数据.3.存 ...

随机推荐

  1. jsp页面时间戳转换为时间格式

    jstl中格式化时间戳   在jsp页面中使用jstl标签将long型的时间戳转换为格式化后的时间字符串 1.通过<jsp:useBean /> 导入java.util.Date类2.通过 ...

  2. jackson 用法总结

    1.序列化与反序列化封装 private static final Logger logger = LoggerFactory.getLogger(JsonUtil.class); /** * Obj ...

  3. C#常用工具类——Excel操作类(ZT)

    本文转载于: http://www.cnblogs.com/zfanlong1314/p/3916047.html /// 常用工具类——Excel操作类 /// <para> ----- ...

  4. Dubbo 源码分析 - 集群容错之 LoadBalance

    1.简介 LoadBalance 中文意思为负载均衡,它的职责是将网络请求,或者其他形式的负载"均摊"到不同的机器上.避免集群中部分服务器压力过大,而另一些服务器比较空闲的情况.通 ...

  5. git添加远程仓库

    3种方式 # 未创建项目目录git clone https://github.com/xxx/zzz.git [这里指定目标文件夹,不填写,默认创建 zzz目录] # 已存在项目文件,未设置远程仓库的 ...

  6. PHP的会话控制

    页面数据的作用域: 当前页共享数据:变量.常量 两个页面间传递数据:get,post 跟踪用户的多页面数据共享(会话):session.cookie 全局数据共享:文件.数据库.memcached C ...

  7. Hashtable 为什么不叫 HashTable?

    前几天在写<HashMap 和 Hashtable 的 6 个区别>这篇文章的时候,差点把 Hashtable 写成了 HashTable,后来看源码证实了是:Hashtable,小写的 ...

  8. 访问iis出现500.21错误

    上图是错误的界面 刚开始接手了一个项目,然后想发布到iis上访问使用效果,结果出现了上面的问题,最开始以为是  .net Framework版本的问题,每个版本都试过了,结果问题并没有完全解决. 下面 ...

  9. 异步请求中jetty处理ServletRequestListener的坑

    标题起得比较诡异,其实并不是坑,而是jetty似乎压根就没做对异步request的ServletRequestListener的特殊处理,如果文中有错误欢迎提出,可能自己有所疏漏了. 之前遇到了一个b ...

  10. odoo开发笔记 -- div标签代替odoo button写法

    odoo开发笔记 -- div标签代替odoo button写法 并调用自定义js <footer> <div id="confirm_request_cloud_repo ...