Golang指针隐式间接引用
1、Golang指针
在介绍Golang指针隐式间接引用前,先简单说下Go 语言的指针 (Pointer),一个指针可以指向任何一个值的内存地址 它指向那个值的内存地址,在 32 位机器上占用 4 个字节,在 64 位机器上占用 8 个字节,并且与它所指向的值的大小无关。大致上理解如下:
- 变量名前的 & 符号,是取变量的内存地址,不是取值;
- 数据类型前的 * 符号,代表要储存的是对应数据类型的内存地址,不是存值;
- 变量名前的 * 符号,代表从内存地址中取值 (Dereferencing)。
使用一个指针引用一个值被称为间接引用。
注意 1:golang 指针Dereferencing(解引用)是什么意思?
在 Go 语言中,指针解引用(dereferencing)是指通过指针访问指针所指向的内存地址上存储的值。在指针变量前加上 * 符号可以进行指针解引用操作。指针解引用会返回指针所指向的内存地址上存储的值。例如,假设有一个指向int类型变量的指针:
var x int = 42
var p *int = &x要访问p指针指向的值,可以使用指针解引用:
fmt.Println(*p) // 输出:42可以看到,使用操作符访问指针指向的值时,需要将其放置在指针变量的前面。如果尝试使用操作符访问一个空指针,会引发运行时错误。因此,在解引用指针之前,通常需要确保指针不是空指针。
注意 2:在Go语言中,直接砍掉了 C 语言指针最复杂的指针运算部分,只留下了获取指针(
&运算符)和获取对象(*运算符)的运算,用法和C语言很类似。但不同的是,Go语言中没有->操作符来调用指针所属的成员,而与一般对象一样,都是使用.来调用。注意 3:Go 语言中一个指针被定义后没有分配到任何变量时,它的值为
nil。
2、new函数
在 Go 语言中,new 函数用于动态地分配内存,返回一个指向新分配的零值的指针。它的语法如下:
func new(Type) *Type
其中,Type 表示要分配的内存的类型,new 函数返回一个指向 Type 类型的新分配的零值的指针。但是需要注意的是,new 函数只分配内存,并返回指向新分配的零值的指针,而不会初始化该内存。
注意 1:用new(structName):这个方法得到的是*structName类型,即类的指针类型;用structName{init para}:这个方法得到的是structName类型,即类的实例类型,不是指针。
注意 2:new函数更多细节介绍请参见《Go语言new( )函数》这篇博文。
3、Golang指针隐式间接引用
Go 语言自带指针隐式解引用 :对于一些复杂类型的指针, 如果要访问成员变量时候需要写成类似*p.field的形式时,只需要p.field即可访问相应的成员。以下复杂类型自带指针隐式解引用:
3.1 结构体类型指针隐式间接引用
结构体字段可以通过结构体指针来访问。如果我们有一个指向结构体的指针 p,那么可以通过 (*p).X 来访问其字段 X。不过这么写太啰嗦了,所以语言也允许我们使用隐式间接引用,直接写 p.X 就可以。示例代码如下:
package main import (
"fmt"
) type Student struct {
name string
age int
weight float32
score []int
} func main(){
pp := new(Student) //使用 new 关键字创建一个指针
*pp = Student{"qishuangming", 23, 65.0, []int{2, 3, 6}}
fmt.Printf("stu pp have %d subjects\n", len((*pp).score)) //按照我们对指针的了解,对Student结构体对象pp显示赋值的话需要使用解引用语法进行赋值,但是实际编码时都会省去*,写法如下行所示。
fmt.Printf("stu pp have %d subjects\n", len(pp.score)) //编译器会自动将指针解引用,并访问结构体中的对应字段,这个过程被称为隐式间接引用。
}
3.2 数组类型指针隐式间接引用
同样指向数组的指针可以隐式解引用数组中的元素。
var arr [3]int
p := &arr
p[0] = 1 // 等价于 (*p)[0] = 1
3.3 切片类型指针隐式间接引用
切片实际上是对底层数组的封装,因此指向切片的指针可以隐式解引用切片中的元素。
s := []int{1, 2, 3}
p := &s
p[0] = 4 // 等价于 (*p)[0] = 4
3.4 字典类型隐式间接引用
map 是引用类型,当我们使用 map 类型的变量访问元素时,也不需要使用 * 运算符进行解引用,Golang 会自动帮我们解引用。
m := map[string]int{"a": 1, "b": 2}
fmt.Println(m["a"]) // 隐式解引用
3.5 func 类型隐式间接引用
在 Golang 中,函数类型也是一种类型,它可以使用指针类型来表示函数的地址。如果我们定义了一个函数类型的变量,并将一个函数的地址赋值给它,那么我们可以直接调用该变量,并且不需要使用 * 运算符进行解引用。
例如,以下代码演示了函数类型指针的隐式解引用:
type Add func(a, b int) int
func main() {
var add Add
add = func(a, b int) int {
return a + b
}
sum := add(1, 2) // 隐式解引用
fmt.Println(sum)
}
在上面的代码中,我们定义了一个函数类型 Add,它接受两个 int 类型的参数并返回一个 int 类型的值。我们定义了一个变量 add,它的类型是 Add。我们将一个函数的地址赋值给了 add 变量,然后直接调用了 add 变量,不需要使用 * 运算符进行解引用。
注意 1:函数类型指针的隐式解引用仅适用于函数类型变量的调用,而不适用于访问函数类型变量的成员。如果我们想要访问函数类型变量的成员,还是需要使用
*运算符进行解引用。注意 2:在 Go 中,基本类型(如 int、float、bool 等)以及字符串类型等非引用类型都没有指针隐式解引用的行为。这意味着,如果需要访问基本类型的指针指向的值,必须显式地使用 * 运算符来解引用指针。下面是一个示例:
var i int
p := &i
*p = 1 // 显式解引用指针来修改指针所指向的值
fmt.Println(i) // 输出 1另外,对于基本类型而言,使用指针可能会导致性能下降。因此,在使用指针时应该谨慎,并且只在必要的情况下使用指针来传递数据。
4、总结
在 Go 中,指针隐式解引用是指通过指针直接访问指针所指向的值,而不需要显式地使用 * 运算符来解引用指针。对于一些复杂类型的指针(结构体类型指针、数组/切片类型指针、字典类型、func类型), 如果要访问成员变量时候需要写成类似*p.field的形式时,只需要p.field即可访问相应的成员。
Golang指针隐式间接引用的更多相关文章
- C语言指针间接引用
int a = 10; //普通变量 int *p = &a; //一级指针.是变量的地址. int **pp = &p; //二级指针.是一级指针的地址. int ***ppp = ...
- 错误 C2280 Union : 尝试引用已删除的函数 以及 警告 C4624 “Grade”: 已将析构函数隐式定义为“已删除”的一种解决方法
Union 是C/C++语言中的一种结构类型,用于定义可共享内存的数据变量的一种方式,初次使用Union联合体时可能会遇到以下问题: 错误 C2280 Union : 尝试引用已删除的函数 警告 C4 ...
- 12深入理解C指针之---指针多层间接引用
该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 一.指针多层引用 1.定义:指针可以用不同的间接引用层级,通常使用多重指针或字符数组来 ...
- EL表达式中引用隐式变量
除了在jsp中9大隐式变量(在前面文章也叫预定义变量)在转化成为servlet后_jspService中可以看到: public void _jspService(final javax.servle ...
- 彻底理解c++的隐式类型转换
隐式类型转换可以说是我们的老朋友了,在代码里我们或多或少都会依赖c++的隐式类型转换. 然而不幸的是隐式类型转换也是c++的一大坑点,稍不注意很容易写出各种奇妙的bug. 因此我想借着本文来梳理一遍c ...
- dynamic_cast 和 static_cast 隐式类型转换的区别
首先回顾一下C++类型转换: C++类型转换分为:隐式类型转换和显式类型转换 第1部分. 隐式类型转换 又称为“标准转换”,包括以下几种情况:1) 算术转换(Arithmetic conversion ...
- JSP 4个域对象-9个内置对象-11个EL隐式对象
一. 四大域对象 1. PageContext :页面范围的数据 2. ServletRequest:请求范围的数据 3. HttpSession:会话范围的数据 4. ServletContext: ...
- dll显式加载与隐式加载
使用动态DLL有两种方法,一种是隐式链接,一种是显式链接,如果用loadlibrary就是显示链接,用lib就属于隐式链接. 两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样 ...
- dll的加载方式主要分为两大类,显式和隐式链接
之前简单写过如何创建lib和dll文件及简单的使用(http://blog.csdn.net/betabin/article/details/7239200).现在先再深入点写写dll的加载方式. d ...
- QStringLiteral(源代码里有一个通过构造函数产生的从const char*到QString的隐式转换,QStringLiteral字符串可以放在代码的任何地方,编译期直接生成utf16字符串,速度很快,体积变大)
原作者: Olivier Goffart 点击打开链接http://woboq.com/blog/qstringliteral.html 译者: zzjin 点击打开链接http://www.tuic ...
随机推荐
- Java笔记第九弹
升级版: 数据安全问题的解决 1.同步代码块 (弊端:降低了运行效率) 格式:(锁--同一把锁) synchronized(任意对象){ 多条语句操作共享数据的代码 } //sellTicket.ja ...
- Android笔记--按钮触控
Button(由TextView派生而来) 但也是有一定的区别: 具体实现: 按钮控件的新增属性 具体实现: 在未使用textAllCaps属性之前,按钮名称会默认为全部使用大写字母: 在指定了该属性 ...
- 关于jsp页面中的小细节们
细节一:利用jsp判断文本框的输入格式是否正确 也就是主要利用script标签进行判断,主要用到的是正则表达式(判断是否为整数): 再加上if语句的配合,就能够在文本框的格式不正确时,发出错误警告啦! ...
- CSS必知必会
CSS概念 css的使用是让网页具有统一美观的页面,css层叠样式表,简称样式表,文件后缀名.css css的规则由两部分构成:选择器以及一条或者多条声明 选择器:通常是需要改变的HTML元素 声明: ...
- call、apply 及 bind 函数
首先从以下几点来考虑如何实现这几个函数 不传入第一个参数,那么上下文默认为 window: 改变了 this 指向,让新的对象可以执行该函数,并能接受参数. 实现call 首先 context 为可选 ...
- PyQt5学习 (4)--QAbstractButton(下)
QAbstractBUtton: 所有按钮控件的基类 提供按钮的通用功能 继承自QWidget 属于抽象类别,不能直接去使用,必须借助于子类(除非你觉得子类不够用,想自定义一个按钮) ...
- CISCN2021东北赛区-Maple_root-WriteUp
参赛队员: x0r,b477eRy,f1oat 总结 最终成绩:3627 最终排名:13 一血数量:3 本次比赛前期一切顺利,后期感觉被py爆了,结果名次就拉了下来,整体题目全部都偏向MISC,打的很 ...
- 浅学git工具
1.git工具介绍及使用 git工具直接安装: 直接运行exe文件进行安装,按默认的操作点击下一步就行了 校验: 在DOS命令行中输入:git --version 如果能正常显示出对应的版本就是ok ...
- 单机最快的队列Disruptor解析和使用
前言 介绍高性能队列Disruptor原理以及使用例子. Disruptor是什么? Disruptor是外汇和加密货币交易所运营商 LMAX group 建立高性能的金融交易所的结果.用于解决生产者 ...
- 迁移学习()《Attract, Perturb, and Explore: Learning a Feature Alignment Network for Semi-supervised Domain Adaptation》
论文信息 论文标题:Attract, Perturb, and Explore: Learning a Feature Alignment Network for Semi-supervised Do ...