Go 学习笔记(13)— 指针定义、指针特点、空指针、指针数组、指向指针的指针、指针作为函数入参
1. 复合数据类型
Go
语言基本的复合数据类型有指针、数组、切片、字典、通道、结构和接口等。格式如下:
* pointerType // 指针类型,
[n]elementType // 数组类型,
[]elementType // 切片类型,
map [keyType]valueType // 字典类型
chan valueType // 通道类型// 结构体类型
struct {fieldType fieldTypefieldType fieldType...
}// 接口类型
interface {method1(inputParams) (returnParams)method2(inputParams) (returnParams)...
}
2. 指针定义
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go 语言中使用在变量名前面添加&
操作符(前缀)来获取变量的内存地址(取地址操作),格式如下:
ptr := &v // v 的类型为 T
其中 v
代表被取地址的变量,变量 v
的地址使用变量 ptr
进行接收, ptr
的类型为*T
,称做 T 的指针类型,*
代表指针。
Go
语言的取地址符是 &
,放到一个变量前使用就会返回相应变量的内存地址。
获取变量在内存中地址:
package mainimport "fmt"func main() {var a int = 10fmt.Printf("变量的地址: %x\n", &a) // 变量的地址: c000018068fmt.Printf("%p", &a) // %p 打印变量内存地址,指针的值是带有0x十六进制前缀的一组数据。
}
一个指针变量指向了一个值的内存地址。在使用指针前你需要声明指针。指针声明格式如下:
var varName *varType
varType
为指针类型, varName
为指针变量名, *
号用于指定变量是作为一个指针。以下是有效的指针声明:
var ip *int /* 指向整型*/
var fp *float32 /* 指向浮点型 */
Go
同样支持多级指针,类似 **ip
。
一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。
当一个指针被定义后没有分配到任何变量时,它的默认值为 nil
。指针变量通常缩写为 ptr
。
变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址。
3. 指针使用
指针使用流程:
- 定义指针变量
- 为指针变量赋值
- 访问指针变量中指向地址的值
在指针类型前面加上 *
号(前缀)来获取指针所指向的内容。
使用示例:
package mainimport "fmt"func main() {var a int= 20 /* 声明实际变量 */var ip *int /* 声明指针变量 */ip = &a /* 指针变量的存储地址 */fmt.Printf("a 变量的地址是: %x\n", &a )/* 指针变量的存储地址 */fmt.Printf("ip 变量储存的指针地址: %x\n", ip )/* 使用指针访问值 */fmt.Printf("*ip 变量的值: %d\n", *ip )
}
输出结果为:
a 变量的地址是: 20818a220
ip 变量储存的指针地址: 20818a220
*ip 变量的值: 20
以下几点使用指针的建议:
不要对
map
、slice
、channel
这类引用类型使用指针;如果需要修改方法接收者内部的数据或者状态时,需要使用指针;
如果需要修改参数的值或者内部数据时,也需要使用指针类型的参数;
如果是比较大的结构体,每次参数传递或者调用方法都要内存拷贝,内存占用多,这时候可以考虑使用指针;
像
int
、bool
这样的小数据类型没必要使用指针;如果需要并发安全,则尽可能地不要使用指针,使用指针一定要保证并发安全;
指针最好不要嵌套,也就是不要使用一个指向指针的指针,虽然
Go
语言允许这么做,但是这会使你的代码变得异常复杂;
4. 指针特点
在赋值语句中,
*p
出现在=
左边表示是指针声明,*p
出现在=
右边表示取指针指向的值;结构体指针访问结构体字段仍然使用
.
点操作符,Go
不支持->
操作符;Go
不支持指针的运算;函数中允许返回变量的地址;
package mainimport "fmt"// Phone is struct type 注释开头必须是 结构体或者方法的名字,后面再加空格
type Phone struct { //exported type Phone should have comment or be unexportedgo-lintmodel stringcolor stringprice int
}func main() {var a *int = nilvar b *intc := 10b = &ce := *bphone := Phone{"huawei", "blue", 1000}p := &phone// p++ invalid operation: p++ (non-numeric type *Phone)fmt.Printf("a is %v, a type is %T\n", a, a)fmt.Printf("b is %v, b type is %T\n", b, b)fmt.Printf("e is %v, e type is %T\n", e, e)fmt.Printf("p is %v, p type is %T\n", p, p)fmt.Printf("p.model is %v, p.price is %v\n", p.model, p.price)result := sum(5, 3)fmt.Printf("result is %v, result type is %T\n", *result, result)}func sum(a, b int) *int {ret := a + breturn &ret
}
输出结果:
a is <nil>, a type is *int
b is 0xc000016068, b type is *int
e is 10, e type is int
p is &{huawei blue 1000}, p type is *main.Phone
p.model is huawei, p.price is 1000
result is 8, result type is *int
对变量进行取地址操作使用
&
操作符,可以获得这个变量的指针变量;对指针变量进行取值操作使用
*
操作符,可以获得指针变量指向的原变量的值;
5. Go 空指针
当一个指针被定义后没有分配到任何变量时,它的值为 nil
。 nil
指针也称为空指针。 nil
在概念上和其它语言的 null
、 None
、 nil
、 NULL
一样,都指代零值或空值。
空指针值为 nil,即没有内存地址,是不能进行赋值操作的,比如下面的示例:
var intP *int
*intP =10
运行的时候会提示 invalid memory address or nil pointer dereference
。这时候该怎么办呢?其实只需要通过 new
函数给它分配一块内存就可以了,如下所示:
var intP *int = new(int)
//更推荐简短声明法,这里是为了演示
//intP:=new(int)
一个指针变量通常缩写为 ptr
。空指针判断方法:
if(ptr != nil) /* ptr 不是空指针 */
if(ptr == nil) /* ptr 是空指针 */
使用示例:
package mainimport "fmt"func main() {var ptr *intfmt.Printf("ptr 的值为 : %x\n", ptr )
}
输出结果为:
ptr 的值为 : 0
6. Go 指针数组
ptr
为整型指针数组。因此每个元素都指向了一个值。以下实例的三个整数将存储在指针数组中:
package mainimport "fmt"const MAX int = 3func main() {a := []int{10,100,200}var i intvar ptr [MAX]*int; // 声明了整型指针数组for i = 0; i < MAX; i++ {ptr[i] = &a[i] /* 整数地址赋值给指针数组 */}for i = 0; i < MAX; i++ {fmt.Printf("a[%d] = %d\n", i,*ptr[i] )}
}
7. Go 指向指针的指针
如果一个指针变量存放的又是另一个指针变量的地址,则称这个指针变量为指向指针的指针变量。当定义一个指向指针的指针变量时,第一个指针存放第二个指针的地址,第二个指针存放变量的地址:
访问指向指针的指针变量值需要使用两个 *
号,如下所示:
package mainimport "fmt"func main() {var a intvar ptr *intvar pptr **inta = 3000/* 指针 ptr 地址 */ptr = &a/* 指向指针 ptr 地址 */pptr = &ptr/* 获取 pptr 的值 */fmt.Printf("变量 a = %d\n", a )fmt.Printf("指针变量 *ptr = %d\n", *ptr )fmt.Printf("指向指针的指针变量 **pptr = %d\n", **pptr)
}
8. Go 指针作为函数参数
Go
语言允许向函数传递指针,只需要在函数定义的参数上设置为指针类型即可。
ackage mainimport "fmt"func main() {/* 定义局部变量 */var a int = 100var b int= 200fmt.Printf("交换前 a 的值 : %d\n", a )fmt.Printf("交换前 b 的值 : %d\n", b )/* 调用函数用于交换值* &a 指向 a 变量的地址* &b 指向 b 变量的地址*/swap(&a, &b);fmt.Printf("交换后 a 的值 : %d\n", a )fmt.Printf("交换后 b 的值 : %d\n", b )
}func swap(x *int, y *int) {var temp inttemp = *x /* 保存 x 地址的值 */*x = *y /* 将 y 赋值给 x */*y = temp /* 将 temp 赋值给 y */
}
Go 学习笔记(13)— 指针定义、指针特点、空指针、指针数组、指向指针的指针、指针作为函数入参相关推荐
- mybatis学习笔记(13)-延迟加载
2019独角兽企业重金招聘Python工程师标准>>> mybatis学习笔记(13)-延迟加载 标签: mybatis [TOC] resultMap可以实现高级映射(使用asso ...
- opencv进阶学习笔记13:图像形态学操作大全(膨胀,腐蚀,开闭,黑帽,顶帽,梯度)python版
基础版学习笔记: python3+opencv学习笔记汇总目录(适合基础入门学习) 进阶版笔记目录链接: python+opencv进阶版学习笔记目录(适合有一定基础) 基础版形态学: opencv学 ...
- mysql分页概念_MySQL学习笔记之数据定义表约束,分页方法总结
本文实例讲述了MySQL学习笔记之数据定义表约束,分页方法.分享给大家供大家参考,具体如下: 1. primary key 主键 特点:主键是用于唯一标识一条记录的约束,一张表最多只能有一个主键,不能 ...
- Linux学习笔记13
Linux学习笔记13 Linux学习笔记13 配置Nagios 基本介绍 Nagios安装 - 服务端 Nagios安装 - 客户端 监控中心添加被监控主机 配置文件的简单说明 继续添加需要服务端通 ...
- 台大李宏毅Machine Learning 2017Fall学习笔记 (13)Semi-supervised Learning
台大李宏毅Machine Learning 2017Fall学习笔记 (13)Semi-supervised Learning 本博客参考整理自: http://blog.csdn.net/xzy_t ...
- 【计算机网络学习笔记13】交换技术(下)
[计算机网络学习笔记13]交换技术(下) 一.生成树的诞生和发展 1. 环路问题 两个网桥之间的连接网线如果只有一根,而这根网线或者接口有问题,网络就会出现单点故障.所以为了提高可靠性,网桥在互连时一 ...
- Hadoop学习笔记—13.分布式集群中节点的动态添加与下架
Hadoop学习笔记-13.分布式集群中节点的动态添加与下架 开篇:在本笔记系列的第一篇中,我们介绍了如何搭建伪分布与分布模式的Hadoop集群.现在,我们来了解一下在一个Hadoop分布式集群中,如 ...
- java 量化指标_量化投资学习笔记13——各种指标的绘图、计算及交易策略
<量化投资:以python为工具>第五部分笔记 先来画k线图,要注意finance模块已经从matplotlib库中去除,现在要用mpl_finance库,单独安装. 其中有candles ...
- R语言小白学习笔记13—基本统计
R语言小白学习笔记13-基本统计 笔记链接 学习笔记13-基本统计 13.1 概括性统计量 13.2 相关系数和协方差 13.3 t-检验 13.3.1 单样本t检验 13.3.2 两样本t检验 13 ...
- Excel VBA 学习笔记13:单元格的格式
Excel VBA 学习笔记13:单元格的格式 NumberFormat 属性 (Excel) vba excel 单元格格式设置 Excel VBA 单元格格式 python解决SNIMissing ...
最新文章
- 如何有效使用Project(1)——编制进度计划、保存基准
- python—多线程之数据混乱问题
- nodejs开发游戏服务器遇到的性能问题
- DICOM文件格式与编程(转)
- silverlight 使用IValueConverter 转换
- mysql8 php7_在centos7安装nginx+mysql8+php7(LNMP)
- 计算机图形标定学,计算机图形学(璩柏青)第10章空间形体的三维重建与图像处理.ppt...
- HDU 1492 The number of divisors(约数) about Humble Numbers
- Spark提交 指定 kerberos 认证信息
- QTP中VBS脚本下FSO、WSH的应用(二)
- windows nginx 停止和启动_nginx在window与linux中启动、停止、与关闭
- 搜索指定期刊下的领域相关文章
- socket,ioctl获取ip
- 修复Linux系统内核TCP漏洞,Linux 内核中TCP SACK机制远程Dos漏洞处理方法(CVE-2019-11477) | 聂扬帆博客...
- pccad 电气元件_CAD电气元件库谁有?
- Selenium使用之——键盘操作方法
- 阿里巴巴牵手福特 共同打造智联网汽车
- tk域名管理后台_TK域名解析教程,dns设置教程
- Origin | 堆叠柱状图 | 多列(分组)堆积柱状图
- 终于明白为什么人人都爱Django了,Django果然天下第一
热门文章
- 2022-2028年中国铁路机车行业投资分析及前景预测报告
- 取消打开命令行进入默认anaconda的环境
- PyTorch官方中文文档:torch.optim 优化器参数
- LeetCode中等题之特殊等价字符串组
- LeetCode简单题之设计 Goal 解析器
- LeetCode简单题之寻找比目标字母大的最小字母
- MySQL最新版8.0.21安装配置教程~
- Error: Gradle project sync failed. Please fix your project and try again.
- Android intent 接受值的内容为空
- Android 多渠道打包