什么是指针?

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

在上面的例子中,变量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. Windows server install mrtg

    由于MRTG使用Perl语言编写 , 安装ActivePerl http://downloads.activestate.com/ActivePerl/releases/5.20.1.2000/Act ...

  2. Android自带Monkey测试

    Monkey是在模拟器上或设备上运行的一个小程序,它能够产生为随机的用户事件流,例如点击(click),触摸(touch),挥手(gestures),还有一系列的系统级事件.可以使用Monkey来给正 ...

  3. 【BZOJ3576】江南乐(博弈论)

    [BZOJ3576]江南乐(博弈论) 题面 BZOJ 洛谷 题解 无论一堆石头怎么拆分,都并不能改变它是一个\(Multi-SG\)的事实. 既然每一组的\(F\)都是固定的,那么我们预处理所有的可能 ...

  4. emwin之自绘制 BUTTON 图形的一些问题

    @2018-11-8 [小记] [需求] 官方只提供圆角矩形图形,其他图形及颜色需求则要自己实现 [注意] 通过回调函数自实现的图形绘制存在该回调函数一直被调用的现象,而非像窗口回调函数中 BUTTO ...

  5. 小程序-camera

    camera 使用这个组件使用手机的拍摄功能.实现如下操作 打开拍摄画面,在手机上半屏显示拍摄取景,下面有一个拍摄按钮.点击后,取景器位置显示拍摄画面,下面显示确定取消按钮. 确定后,下方的预览图片列 ...

  6. [WC2008]游览计划 解题报告

    [WC2008]游览计划 斯坦纳树板子题,其实就是状压dp 令\(dp_{i,s}\)表示任意点\(i\)联通关键点集合\(s\)的最小代价 然后有转移 \[ dp_{i,S}=\min_{T\in ...

  7. LVM-COW写实备份

    [root@localhost ~]# fdisk -l /dev/sdb /dev/sdc | grep "LVM"/dev/sdb1 1 9660 77593918+ 8e L ...

  8. 使用jvisualVm监控本地和远程的jvm

    jvisualVm是jdk自带的可视化监控工具,功能很强大,可安装各种扩展插件.本篇不打算讲解如果使用详细的功能,只讲在windows环境怎么监控本地和远端(一般是无界面的linux系统)的java进 ...

  9. MySQL -- 单行函数

    大小写控制函数 SELECT LOWER('HelloWrold'), UPPER('HelloWorld'); 字符控制函数 SELECT REPLACE('abcdababab','p','m') ...

  10. js jquery select 操作 获取值,选中选项,增加,修改,删除

    select示例: <select id="sel"> <option value="1">one</option> < ...