• Go语言结构体指针


    golang结构体指针

    引言:在go语言中,我们如何修改一个的结构体的属性呢?

    type Student struct {
    	Name string
    }
    
    • 1
    • 2
    • 3

    修改失败案例

    package main
    
    import "fmt"
    
    //定义一个结构体 属性Name
    type Student struct {
    	Name string
    }
    
    //方法接收者 :即我们附加在函数名前面的参数
    //类型为Student
    //方法没有返回类型
    func (s Student) FixNameMethod1(name string) {
    	s.Name = name
    }
    
    func main() {
    
    	s := Student{"xiaozhu"}
    	fmt.Println("原有名字:", s.Name)
    
    	
    	fmt.Println("使用方法1修改名字")
    	s.FixNameMethod1("xiaolan")
    	fmt.Println("修改后的名字:", s.Name)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    运行程序后我们发现案例1并没有修改成功

    image-20220914213748439

    分析

    我们创建的s想要调用FixNameMethod1,实参是按照值传递的,所以FixNameMethod1接收到的是实参的副本,也就是s的复制品。既然是副本,那么我们在FixNameMethod1修改形参接收者的属性并不会影响到实参本身的属性

    修改成功案例

    package main
    
    import "fmt"
    
    //定义一个结构体 属性Name
    type Student struct {
    	Name string
    }
    
    //方法接收者参数类型为*Student
    func (s *Student) FixNameMethod2(name string) {
    	s.Name = name
    }
    
    func main() {
    
        s := Student{"xiaozhu"}
    	fmt.Println("原有名字:", s.Name)
    
    	
    	fmt.Println("使用方法1修改名字")
    	s.FixNameMethod1("xiaolan")
    	fmt.Println("修改后的名字:", s.Name)
    
    
    	fmt.Println("使用方法2修改名字")
    	FixNameMethod2("lanlan")
    	fmt.Println("修改后的名字:", s.Name)
    
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    运行程序后发现这次修改成功

    image-20220914214050223

    分析

    我们本次方法接收者使用的参数类型是一个指向Student类型的指针,这样我们就间接的修改了实参变量

    后续

    但是在学习过程中 又遇到了一个新的问题

    //方法接收者参数类型为*Student
    func (s *Student) FixNameMethod2(name string) {
    	s.Name = name
    }
    
    • 1
    • 2
    • 3
    • 4

    上述方法的方法接收者的类型是一个指向Student指针类型(*Student),而我传递给它的是一个s := Student{"xiaozhu"}, 这并不是一个指针。

    那我们为什么可以修改成功呢?我又修改了一下代码加以验证

    //s.FixNameMethod2("lanlan") 修改为以下代码
    (&s).FixNameMethod2("lanlan")
    
    • 1
    • 2

    发现名称果然可以修改成功

    image-20220914214250336

    分析

    s.FixNameMethod2("lanlan") //相当于隐式的转化为(&s).FixNameMethod2("lanlan")
    
    • 1

    我们使用未修改前的语句时,实参接收者是Student类型的变量,形参接收者是*Student类型的变量,go的编译器会隐式的获取变量的地址, 因此我们可以修改成功

    补充一点,我们上面的方法修改值的过程中,直接使用了 (s.Name = name)指针 . 属性的方式。

    //方法接收者参数类型为*Student
    func (s *Student) FixNameMethod2(name string) {
    	s.Name = name
    }
    
    • 1
    • 2
    • 3
    • 4

    我们在c/c++当中使用的是->操作符来访问成员

    举个例子

    如果 him == &barney , 那么 him->income ,即是barney.income

    但是在go语言中,编译器是帮我们隐式的解引用获取实际的值,因此我们完整的写下来是:

    (*s).Name = name
    
    • 1

    指针Or结构体

    那么我们的方法接收者的参数类型何时使用指针类型 何时使用结构体类型呢?

    go语言中所有的函数参数都是值拷贝。如果结构体较大,一般使用指针参数,这样可以避免复制整个实参,并且如果要在函数修改结构体的属性,则必须使用指针参数。

    再总结一下

    使用指针的优点

    • 执行快,效率高
    • 可以修改数据

    使用指针的缺点

    • 无法保护数据,原始数据容易修改

    使用结构体的优点

    • 处理的是原始数据的副本,这样保护了原始数据
    • 代码风格非常清晰明了(更贴近于java语言)

    使用结构体的缺点

    • 不能修改属性
    • 传递结构体浪费时间和空间,尤其是较大的结构体

    参考书籍:《Go程序设计语言》、《C Primer Plus》
    如有错误和冒犯,欢迎指出

  • 相关阅读:
    解读随机生成密钥存文件的python代码
    Unity游戏Mod/插件制作教程04 - 如何创建配置文件
    CefSharp方法汇总
    解决from d2l import torch as d2l报pandas,numpy的相关问题
    如何安全地配置 AWS EC2 实例
    C- wait() & waitpid() & status变量
    SpringBoot集成easyexcel实现动态模板导出
    Java多线程学习入门(六):锁升级、锁消除、锁粗化
    选择排序超详细讲解C语言
    安装OpenGL
  • 原文地址:https://blog.csdn.net/qq_54650406/article/details/126861335