Golang指针隐式间接引用详解

 更新时间:2023年05月16日 08:39:54   作者:人艰不拆_zmc  
在 Go中,指针隐式解引用是指通过指针直接访问指针所指向的值,而不需要显式地使用 * 运算符来解引用指针,这篇文章主要介绍了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.5func 类型隐式间接引用

在 Golang 中,函数类型也是一种类型,它可以使用指针类型来表示函数的地址。如果我们定义了一个函数类型的变量,并将一个函数的地址赋值给它,那么我们可以直接调用该变量,并且不需要使用 * 运算符进行解引用。

例如,以下代码演示了函数类型指针的隐式解引用:

type Add func(a, b int) int
func main() {
    var add Add
    add = func(a, b int) int {
        return a + b
    }
    println(add) //0x10cf168
    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指针隐式间接引用的文章就介绍到这了,更多相关Golang指针内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Golang IOT中的数据序列化与解析过程

    Golang IOT中的数据序列化与解析过程

    这篇文章主要介绍了Golang IOT中的数据序列化与解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • 在Golang代码中如何自动生成版本号的方法示例

    在Golang代码中如何自动生成版本号的方法示例

    这篇文章主要给大家介绍了在Golang代码中如何自动生成版本号的相关资料,文中通过示例代码介绍的非常详细,对大家具有一定的参考学习价值,需要的朋友们下面来一起看看吧。
    2017-07-07
  • Go语言自定义linter静态检查工具

    Go语言自定义linter静态检查工具

    这篇文章主要介绍了Go语言自定义linter静态检查工具,Go语言是一门编译型语言,编译器将高级语言翻译成机器语言,会先对源代码做词法分析,词法分析是将字符序列转换为Token序列的过程,文章详细介绍需要的小伙伴可以参考一下
    2022-05-05
  • Go语言中切片使用的注意事项小结

    Go语言中切片使用的注意事项小结

    切片是引用类型,相信对大家来说都不陌生,下面这篇文章主要给大家总结介绍了关于Go语言中切片使用的一些注意事项,文中通过示例代码介绍的非常详细,需要的朋友可以参考借鉴,下面随着小编来一起学习学习吧。
    2018-01-01
  • Go语言入门13之runtime包案例讲解

    Go语言入门13之runtime包案例讲解

    这篇文章主要介绍了Go语言入门runtime包相关知识,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-05-05
  • Golang通脉之map详情

    Golang通脉之map详情

    这篇文章主要介绍了Golang通脉之map,Go语言中提供的映射关系容器为map,其内部使用散列表(hash)实现,map 是一种无序的键值对的集合。map 最重要的一点是通过 key 来快速检索数据,key 类似于索引,指向数据的值 map 是一种集合,所以可以像迭代数组和切片那样迭代它
    2021-10-10
  • 使用Go语言创建静态文件服务器问题

    使用Go语言创建静态文件服务器问题

    这篇文章主要介绍了使用Go语言创建静态文件服务器,本文通过试了代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-03-03
  • 一文带你掌握Go语言运算符的使用

    一文带你掌握Go语言运算符的使用

    运算符用于在程序运行时执行数学或逻辑运算。Go 语言内置的运算符有:算术运算符、关系运算符、逻辑运算符、位运算符、赋值运算符、其他运算符。本文将带大家详细了解一下这些运算符的使用,感兴趣的可以了解一下
    2022-04-04
  • Golang高性能持久化解决方案BoltDB数据库介绍

    Golang高性能持久化解决方案BoltDB数据库介绍

    这篇文章主要为大家介绍了Golang高性能持久化解决方案BoltDB数据库介绍,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步
    2021-11-11
  • Go实现生产随机密码的示例代码

    Go实现生产随机密码的示例代码

    这篇文章主要为大家详细介绍了如何利用Go实现生产随机密码的,文中的示例代码简洁易懂,具有一定的借鉴价值,有需要的小伙伴可以参考一下
    2023-09-09

最新评论