什么是指针?

指针是一个变量,用于存储另一个变量的内存地址。

在上面的例子中,变量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)
}

&运算符用于获取变量的地址。 在上面的程序中,我们将b的地址赋给一个类型为* int的类型。 据说现在a指向b。 当我们在a中打印该值时,b的地址将被打印。 这个程序输出

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_01.go"
Type of a is *int
address of b is 0xc042054080

你可能会得到一个不同的b地址,因为b的位置可以在内存中的任何地方。执行两次得到的结果  

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_01.go"
Type of a is *int
address of b is 0xc042054080 [Done] exited with code=0 in 11.167 seconds [Running] go run "d:\GoProject\src\golang-study-line\basic-02\tempCodeRunnerFile.go"
Type of a is *int
address of b is 0xc04200e098 [Done] exited with code=0 in 0.954 seconds

空指针

指针的零值为 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的地址。 这个程序输出(同样是执行两次):

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_02.go"
b is <nil>
b after initialization is 0xc042054080 [Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_02.go"
b is <nil>
b after initialization is 0xc042054080

如何引用一个指针

如何引用指针意味着访问指针指向的变量的值。 * 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行中,我们引用并打印它的值。 如预期的那样,它打印出b的值。 该程序的输出是

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_03.go"
address of b is 0xc042054080
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.程序的输出是  

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_04.go"
address of b is 0xc04200e098
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)
}

在上面的程序中,在第4行号。 我们将指针变量b传递给函数改变。 内部转换函数中,使用第8行中的解除引用来更改a的值。该程序输出,  

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_05.go"
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)
}

在上面的程序中的第3行号,我们将数组a的地址传递给修改函数。 在修改函数的第8行中,我们取消引用arr并将90分配给数组的第一个元素。 这个程序输出 

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\tempCodeRunnerFile.go"
[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)
}

这个程序也输出

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_07.go"
[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行中,我们将一个切片传递给修改函数。 切片的第一个元素在修改函数中更改为90。

这个程序输出  

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_08.go"
[90 90 91]

所以避免传递指向数组的指针,使用切片代替它。 这段代码更干净并且是惯用的Go

Go不支持指针算术
Go不支持C语言等其他语言中的指针运算。

package main

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

上面的程序会抛出编译错误

[Running] go run "d:\GoProject\src\golang-study-line\basic-02\basic_pointer_09.go"
# command-line-arguments
basic-02\basic_pointer_09.go:6:6: invalid operation: p++ (non-numeric type *[3]int)

参考:

https://golangbot.com/pointers/

Golang入门教程(十五)指针的更多相关文章

  1. 无废话ExtJs 入门教程十五[员工信息表Demo:AddUser]

    无废话ExtJs 入门教程十五[员工信息表Demo:AddUser] extjs技术交流,欢迎加群(201926085) 前面我们共介绍过10种表单组件,这些组件是我们在开发过程中最经常用到的,所以一 ...

  2. RabbitMQ入门教程(十五):普通集群和镜像集群

    原文:RabbitMQ入门教程(十五):普通集群和镜像集群 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.c ...

  3. SpringBoot入门教程(十五)集成Druid

    Druid是阿里巴巴开源平台上一个数据库连接池实现,它结合了C3P0.DBCP.PROXOOL等DB池的优点,同时加入了日志监控,可以很好的监控DB池连接和SQL的执行情况,可以说是针对监控而生的DB ...

  4. Photoshop入门教程(五):滤镜

    学习心得:滤镜通常用于摄影行业,是安装在相机镜头前用于过滤自然光的附加镜头,从而获得一些特殊的效果.同理,Photoshop的滤镜也是为了产生特殊的效果.Photoshop滤镜分为两类:一种是内部滤镜 ...

  5. RabbitMQ入门教程(十六):RabbitMQ与Spring集成

    原文:RabbitMQ入门教程(十六):RabbitMQ与Spring集成 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https: ...

  6. WCF入门教程(五)配置文件

    WCF入门教程(五)配置文件 服务协定以及实现写好后,需要将相关服务公布出去,就需要HOST来承载,供客户端来调用. 承载服务有两种方式,一种通过配置文件,一种通过代码进行配置.上一章已经介绍了代码方 ...

  7. 无废话ExtJs 入门教程十九[API的使用]

    无废话ExtJs 入门教程十九[API的使用] extjs技术交流,欢迎加群(201926085) 首先解释什么是 API 来自百度百科的官方解释:API(Application Programmin ...

  8. Docker入门教程(五)Docker安全

    Docker入门教程(五)Docker安全 [编者的话]DockOne组织翻译了Flux7的Docker入门教程,本文是系列入门教程的第五篇,介绍了Docker的安全问题,依然是老话重谈,入门者可以通 ...

  9. 无废话ExtJs 入门教程十六[页面布局:Layout]

    无废话ExtJs 入门教程十六[页面布局:Layout] extjs技术交流,欢迎加群(201926085) 首先解释什么是布局: 来自百度词典的官方解释:◎ 布局 bùjú: [distributi ...

  10. 无废话ExtJs 入门教程十四[文本编辑器:Editor]

    无废话ExtJs 入门教程十四[文本编辑器:Editor] extjs技术交流,欢迎加群(201926085) ExtJs自带的编辑器没有图片上传的功能,大部分时候能够满足我们的需要. 但有时候这个功 ...

随机推荐

  1. CCF WC2017 & THU WC2017 旅游记

    day-x 真·旅游 去了杭州的一些景点,打了几场练习赛. day0 报到日 领资料.入住,中午在食堂吃饭,感觉做的挺好的,和二高食堂差不多.晚上还有开幕式. day1~day4 白天讲课,晚上营员交 ...

  2. bzoj 2054: 疯狂的馒头(线段树||并查集)

    链接:https://www.lydsy.com/JudgeOnline/problem.php?id=2054 线段树写法: 点的颜色只取决于最后一次染的颜色,所以我们可以倒着维护,如果当前区间之前 ...

  3. pytorch解决鸢尾花分类

    半年前用numpy写了个鸢尾花分类200行..每一步计算都是手写的  python构建bp神经网络_鸢尾花分类 现在用pytorch简单写一遍,pytorch语法解释请看上一篇pytorch搭建简单网 ...

  4. 缺省源和 Vim 配置

    缺省源 #include <bits/stdc++.h> #define x first #define y second #define pb push_back #define mp ...

  5. poj3926 parade (单调队列+dp)

    题意:有n行路,每行路被分成m段,每一段有长度和权值,要求从最下面一行走到最上面一行某个位置,可以从相邻两行的同一列交点往上走,并且在同一行走的长度要<=K,求走过的最大权值 设f[i][j]为 ...

  6. Windows cmd命令

    运行操作 CMD命令锦集       1. gpedit.msc-----组策略 2. sndrec32-------录音机 3. Nslookup-------IP地址侦测器 ,是一个监测网络中DN ...

  7. Spring 整合 Hibernate 时启用二级缓存实例详解

    写在前面: 1. 本例使用 Hibernate3 + Spring3: 2. 本例的查询使用了 HibernateTemplate: 1. 导入 ehcache-x.x.x.jar 包: 2. 在 a ...

  8. mysql connections

    在使用MySQL数据库的时候,经常会遇到这么一个问题,就是“Can not connect to MySQL server. Too many connections”-mysql 1040错误,这是 ...

  9. js jquery数组去重

    数组去重建议直接使用jquery的 $.unique(arr);方法,此外比较好的方法是本文中的unique3方法比较快用了一个hash表,就是所谓的空间换时间.本文还提供了很多其他写法,都是大同小异 ...

  10. BUG描述规范管理

    BUG:软件系统中存在的可能导致系统出错.失效.死机等问题的错误或缺陷. 描述一个缺陷,需要以下核心要素 标题:用简洁的话描述该缺陷,主要让开发知道这是一个什么样的缺陷 参数设置:Bug的类型(功能/ ...