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指针隐式间接引用的更多相关文章

  1. C语言指针间接引用

    int a = 10; //普通变量 int *p = &a; //一级指针.是变量的地址. int **pp = &p; //二级指针.是一级指针的地址. int ***ppp = ...

  2. 错误 C2280 Union : 尝试引用已删除的函数 以及 警告 C4624 “Grade”: 已将析构函数隐式定义为“已删除”的一种解决方法

    Union 是C/C++语言中的一种结构类型,用于定义可共享内存的数据变量的一种方式,初次使用Union联合体时可能会遇到以下问题: 错误 C2280 Union : 尝试引用已删除的函数 警告 C4 ...

  3. 12深入理解C指针之---指针多层间接引用

    该系列文章源于<深入理解C指针>的阅读与理解,由于本人的见识和知识的欠缺可能有误,还望大家批评指教. 一.指针多层引用 1.定义:指针可以用不同的间接引用层级,通常使用多重指针或字符数组来 ...

  4. EL表达式中引用隐式变量

    除了在jsp中9大隐式变量(在前面文章也叫预定义变量)在转化成为servlet后_jspService中可以看到: public void _jspService(final javax.servle ...

  5. 彻底理解c++的隐式类型转换

    隐式类型转换可以说是我们的老朋友了,在代码里我们或多或少都会依赖c++的隐式类型转换. 然而不幸的是隐式类型转换也是c++的一大坑点,稍不注意很容易写出各种奇妙的bug. 因此我想借着本文来梳理一遍c ...

  6. dynamic_cast 和 static_cast 隐式类型转换的区别

    首先回顾一下C++类型转换: C++类型转换分为:隐式类型转换和显式类型转换 第1部分. 隐式类型转换 又称为“标准转换”,包括以下几种情况:1) 算术转换(Arithmetic conversion ...

  7. JSP 4个域对象-9个内置对象-11个EL隐式对象

    一. 四大域对象 1. PageContext :页面范围的数据 2. ServletRequest:请求范围的数据 3. HttpSession:会话范围的数据 4. ServletContext: ...

  8. dll显式加载与隐式加载

    使用动态DLL有两种方法,一种是隐式链接,一种是显式链接,如果用loadlibrary就是显示链接,用lib就属于隐式链接. 两种方法对于你的程序调用动态库时没有任何区别,只是你在编程时,步骤是不一样 ...

  9. dll的加载方式主要分为两大类,显式和隐式链接

    之前简单写过如何创建lib和dll文件及简单的使用(http://blog.csdn.net/betabin/article/details/7239200).现在先再深入点写写dll的加载方式. d ...

  10. QStringLiteral(源代码里有一个通过构造函数产生的从const char*到QString的隐式转换,QStringLiteral字符串可以放在代码的任何地方,编译期直接生成utf16字符串,速度很快,体积变大)

    原作者: Olivier Goffart 点击打开链接http://woboq.com/blog/qstringliteral.html 译者: zzjin 点击打开链接http://www.tuic ...

随机推荐

  1. 开学考--MIS系统(javaweb的开学练习--网络新闻发布系统)

    关于本次考试的相关理解 看到题目的时候,第一反应是这道题不难,之前已经做过十分类似的题目了,然后对于难度是很有自信的(当然,对于用户的权限管理部分,还是很懵): 而第二反应就是,题量挺大的,我在这有限 ...

  2. 谁会拒绝一个开源的 3D 博客呢?

    说到博客大家一定都不陌生,不管你是深耕职场多年的老鸟,还是在学校努力学习的小鸟,应该都有过一段"装扮"博客的经历,比如:放上喜欢的图片.添加炫酷的交互.换上 DIY 的博客主题等等 ...

  3. 灵感宝盒图谱全新改版!代码实验室开启报名丨RTE NG-Lab 双周报

    前言 RTE NG-Lab 计划已经推出一段时间了,计划目前包含灵感宝盒(Idea Box).代码实验室(Code Lab).独立开发者孵化器(NGLab Incubator)三个项目.我们希望借助这 ...

  4. Git 操作命令清单 入门到精通(保姆级)

    一般来说,日常使用只要记住下图6个命令,就可以了.但是如果你想熟练使用它,要记住大概80个命令. 下面是常用的 Git 命令.几个专用名词的译名如下: Workspace:工作区 Index / St ...

  5. Windows10一劳永逸的禁止更新/恢复更新

    之前发表过一篇文章Windows10彻底关闭自动更新,这篇文章相对复杂了些.而且还是有一定几率会触发从而自动打开更新.下面讲的就是怎么一次性永久关闭更新,即使触发了更新,也不能下载更新,从而达到真正的 ...

  6. 【故障公告】数据库服务器 CPU 近 100% 造成全站故障,雪上加霜难上加难的三月

    数据库服务器 CPU 近 100% 问题几乎每年都要发生一次,上次发生在去年1月31日,每次都是通过主备切换或者重启实例解决,数据库服务用的是阿里云 RDS SQL Server 2016 标准版. ...

  7. ArcMap安装OSM路网数据编辑插件ArcGIS Editor for OSM的方法

      本文介绍在ArcGIS下属的ArcMap软件中,ArcGIS Editor for OpenStreetMap这一工具集插件的下载与安装的具体方法.   ArcGIS Editor for Ope ...

  8. Perceptron, Support Vector Machine and Dual Optimization Problem (3)

    Support Vector Machines Perceptron and Linear Separability 假设存在一个 linear decision boundary,它可以完美地对 t ...

  9. Barplot/pie/boxplot作图详解——R语言

    当数据以简单的可视化的形式呈现时,数据便更具有意义并且更容易理解,因为人眼很难从原始数据中得出重要的信息.因此,数据可视化成为了解读数据最重要的方式之一.条形图和箱线图是了解变量分布的最常用的图形工具 ...

  10. 华为人工智能atlasA800-9000物理服务器离线安装及CANN安装和MindSpore安装和Tensorflow安装

    目录 华为人工智能atlas A800-9000 物理服务器全程离线安装驱动以及CANN安装部署和MindSpore安装部署和Tensorflow安装部署 A800-9000 物理服务器安装驱动 使用 ...