go里面的指针用法
什么是指针
指针是存储一个变量的内存地址的变量。
在上图中,变量 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 的地址赋给 a(a 的类型为 *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里面的指针用法的更多相关文章
- Leetcode刷题之矩阵中的指针用法
矩阵中的指针用法 1 快慢指针 Leetcode27移除元素 给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度.不要使用额外的数组 ...
- C# this指针用法
this指针是什么: 这里有一些面向对象编程的概念需要说明:类(Class)的概念和对象(Object)的概念类是对事物概括,也是C#编码时所有代码归属的基本单位:而对象是对类的实例化,也就是C#里n ...
- c++ 智能指针用法详解
本文介绍c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被c++11弃用. 为什么要使用智能 ...
- C和C指针小记(九)-指针用法1
1. *p++ 最常用的一个指针的用法,就是在循环中用来迭代. *p++ 共有3步操作: 1.++操作符把p所指向的内存中的值复制一份 2.++操作符把p加1(实际是一个p所指内存单元的大小,这也是编 ...
- typedef函数指针用法
typedef void(*vp)(); 将vp声明为一个函数指针类型,该类型的指可以针指向一个没有参数,带空返回值的函数. 调用方法vp p;创建一个vp类型的函数指针p void print(vp ...
- c语言指针用法
一.指针 int t 定义整型变量 int *p p为指向整型数据的指针变量 int a[n] 定义整型数组a,它有n个元素 int *p[n] 定义指针数组p,它由n个指向整形数据的指针元素组成 i ...
- C++中const指针用法汇总
这里以int类型为例,进行说明,在C++中const是类型修饰符: int a; 定义一个普通的int类型变量a,可对此变量的值进行修改. const int a = 3;与 int const a ...
- C语言的指针用法:输入一堆字符,把非字母的删去。
char *p,a[20]; int i; gets(a); //这个语句不同于getchar(),后者只能一次输入一个,而前者可以一次输完所有的字符!!! p=a; //这个语句 ...
- C语言之指针用法总结
C语言指针概述:1.计算机系统中,无论是存入或是取出数据都需要与内存单元打交道,物理器件通过地址编码寻找内存单元.2.地址编码是一种数据,C语言的指针类型正是为了表示这种计算机所特有的地址数据.3.存 ...
随机推荐
- Jenkins获取运行job的用户名
1. Jenkins获取运行job的用户名 需要安装user build vars plugin 插件,然后就可以取到$BUILD_USER_ID变量. user build vars plugin下 ...
- 吴恩达机器学习笔记36-正则化和偏差/方差(Regularization and Bias_Variance)
在我们在训练模型的过程中,一般会使用一些正则化方法来防止过拟合.但是我们可能会正则化的程度太高或太小了,即我们在选择λ 的值时也需要思考与刚才选择多项式模型次数类似的问题. 我们选择一系列的想要测试的
- Java对象的克隆和深浅问题
Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...
- MySql事务的隔离级别及作用
逻辑工作单元遵循一系列(ACID)规则则称为事务. 原子性:保证事务是一系列的运作,如果中间过程有一个不成功则全部回滚,全部成功则成功.保证了事务的原则性. 一致性:一致性指的是比如A向B转100块钱 ...
- AI - 概念(Concepts)
01 - AI.ML与DL的关系 从涵盖范围上来讲,人工智能(AI)大于机器学习(ML)大于深度学习(DL) 人工智能(AI):能够感知.推理.行动和适应的程序: 机器学习(ML):能够随着数据量的增 ...
- HTML一些有趣的东西
1.<head>标签里: <meta http-equiv="Refresh" content="3"/><!--三秒自动刷新-- ...
- 《CLR Via C#》读书笔记:24.运行时序列化
一.什么是运行时序列化 序列化的作用就是将对象图(特定时间点的对象连接图)转换为字节流,这样这些对象图就可以在文件系统/网络进行传输. 二.序列化/反序列化快速入门 一般来说我们通过 FCL 提供的 ...
- oracle 锁表 and 解锁
查询锁定表的相关 SELECT l.session_id sid, s.serial#, l.locked_mode,l.oracle_username, l.os_user_name,s.machi ...
- SpringMVC入门学习三
今天是Springmvc学习的第三天,今天我将主要介绍一下: 常用注解的使用 关于非post.get请求的处理 文件上传与下载 拦截器 常用注解的使用 老大在此 @Controller @Cont ...
- ZooKeeper系列(5):ZooKeeper的日志和快照
ZooKeeper系列文章:https://www.cnblogs.com/f-ck-need-u/p/7576137.html#zk ZooKeeper有两种日志.一种快照.日志分为事务日志和Zoo ...