go中的值传递和指针传递
创始人
2024-11-12 18:34:47
0次

文章目录

  • 1、& 和 *
  • 2、空指针
  • 3、nil
  • 4、用值传递还是指针传递?
  • 5、补充

1、& 和 *

  • &后跟一个变量名,得到的是这个变量的内存地址
  • *int类型的变量,代表这个变量里存的值是int类型的变量的内存地址
  • 数据类型的指针类型,即在其前面加 * 号
  • 指针就是内存地址
package main import(         "fmt" ) func main(){          var age int = 18         //&符号+变量 就可以获取这个变量内存的地址         fmt.Println(&age) //0xc0000a2058                  //ptr是一个变量,自身也有内存地址         //&age就是一个地址,是ptr变量的具体的值         var ptr *int = &age  		//这样直接输出,是ptr这个指针变量的值,即0xc0000a2058         fmt.Println(ptr)                  //ptr这个指针变量自身的地址         fmt.Println("ptr本身这个存储空间的地址为:",&ptr)                  //想获取ptr这个指针或者这个地址指向的那个数据:         fmt.Printf("ptr指向的数值为:%v",*ptr) //ptr指向的数值为:18 }   

在这里插入图片描述

  • 对指针类型的变量再加*,是取真实值,即解引用
x := 10 a := &x // 取变量x的地址,a是一个指向int的指针 (*int 类型)  fmt.Println(*a) // 输出a指向的整数值,即变量x的值,这里将输出 10 

2、空指针

* 虽然可以取到指针类型的真实值(解引用),但对nil解引用,会空指针:panic: runtime error: invalid memory address or nil pointer dereference

比如以下情况:

  • 声明了一个指针变量,未初始化就直接解引用
var a *int fmt.Println(*a)  // 这里将会导致空指针错误 
  • 给一个指针变量赋值nil后解引用
var a *int = nil fmt.Println(*a)  // 这里将会导致空指针错误 
  • 调用了一个返回值是指针类型,但返回结果是nil的函数。此时直接解引用会空指针。
func returnNilPointer() *int {     return nil }  func main() {     var a *int = returnNilPointer()     fmt.Println(*a)  // 这里将会导致空指针错误 }  

对指针类型解引用的正确做法是,先判空:

var ptr *int  if ptr != nil {     fmt.Println(*ptr)  // 安全地解引用ptr } else {     fmt.Println("Pointer is nil")     // 避免解引用nil指针 }  

3、nil

源码:
在这里插入图片描述

  • nil是go语言SDK中预先定义好的
  • 可以使用 == 操作符来比较指针、切片、映射、通道和接口变量是否为 nil
  • nil是指针、接口、切片、映射、通道和函数类型的空值
// 指针 var ptr *int fmt.Println(ptr)  // 输出: nil,即不指向任何有效的内存地址  
// 接口 var iface fmt.Stringer fmt.Println(iface == nil)  // 输出: true,即接口变量不指向任何具体的实现类对象  
// 切片 var s []int fmt.Println(s == nil)  // 输出: true,即表示一个空切片,即长度和容量都为0的切片  
// 映射 var m map[string]int fmt.Println(m == nil)  // 输出: true,表示一个空映射,即不包含任何键值对的映射  
// 通道 var ch chan int fmt.Println(ch == nil)  // 输出: true,即未初始化的通道默认为 nil 
// 定义一个函数类型 HandlerFunc type HandlerFunc func(int) string  // 声明一个 HandlerFunc 类型的变量 handler,但未赋值,其值为nil  var handler HandlerFunc 
  • 因此,在未初始化的通道中发送或者接口数据、在未初始化的map中进行存储或者取值,就会panic,但切片有一点不同
var ch chan int ch <- 1  // 尝试向空通道发送数据会导致panic 

报错:

var m map[string]int m["key"] = 1  // 尝试在空映射中存储值会导致panic 

报错:

  • 只定义,未初始化的切片,其值为nil,表示一个空切片,即长度和容量都为0的切片,此时,直接s[0] = 1就会发生下标越界panic,但用append方法一切正常,append 函数会根据需要自动初始化切片并分配内存
var s []int s[0] = 1	// 越界panic 

在这里插入图片描述

var s []int s = append(s, 1)	// 不会panic或者空指针 
  • 注意,自定义的结构体的空值不是nil,这一点和Java中的null不一样(但如果加了&,即取地址,那就是自定义结构体的指针类型,其空值为nil)

在这里插入图片描述

  • 此外,go中,所有的变量 (包括结构体变量) 在声明时如果没有显式赋值,会被赋予其类型的零值。比如:

在这里插入图片描述

4、用值传递还是指针传递?

什么时候用值传递,什么时候用指针传递?比如向函数调用栈里的下一个方法传递对象A,二者的区别在于,指针传递,传的是对象A的内存地址,传的是一个小巧的地址。值传递,是复制对象A的数据传下去。

之前有个说法:想在调用的函数内部改变对象A的值,就用指针传递,但这句话也不全对,因为用值传递,照样可以实现同样的效果。比如对象A为:

// 矩形 type Rectangle struct { 	Width, Height int } 

此时,要改变矩形的宽,值传递和引用传递(指针传递)的实现如下:

在这里插入图片描述

注意看二者的返回值,值传递,因为不能直接修改原对象,因此,需要将副本对象整个都返回,引用传递,则是一个void方法,因为其接收一个原对象的内存地址,可以直接修改原对象。这两种实现方式,在此时,没有谁优谁劣。

考虑优先使用值传递,原因如下:

  • 对于固定大小的类型(整数、浮点数、小型结构体、小型数组),它们占用的内存大小固定且小,大小与指针大小相当

  • 值传递,代表的意志是:函数收到的是一个副本数据,我只是需要操作这份数据,不会改动你的原始数据

在这里插入图片描述

  • 对于较小的对象,直接值传递,可以避免引用传递时对指针解引用的额外步骤

此外,从底层分析原因:

在这里插入图片描述

最后,如果传递的是一个很大的结构体,那用指针传递更优。

5、补充

关于使用指针类型的场景,还有:insert数据时,数据库中默认值不对的时候:

在这里插入图片描述

=====

最后一篇博客,部门被裁,中午通知,下午走人。纪念人生第一次失业哈哈哈哈哈哈哈哈。

2024年8月2号  12:27 

相关内容

热门资讯

实测交流透视挂!宝玛大厅ai智... 实测交流透视挂!宝玛大厅ai智能透视挂教程,宝玛大厅破解软件经验(本来有挂辅助)1、每一步都需要思考...
总算了解辅助器!朱雀吴江三缺一... 总算了解辅助器!朱雀吴江三缺一ai智能透视辅助挂技巧,朱雀吴江三缺一好像是有挂(有辅助挂细节)朱雀吴...
今日公布透视!九五至尊大厅ai... 今日公布透视!九五至尊大厅ai智能透视插件,九五至尊大厅有没有透视挂窍门(切实有挂技术)1、在九五至...
玩家必看科普开挂!聚闲麻将ai... 玩家必看科普开挂!聚闲麻将ai智能透视辅助挂软件,聚闲麻将总是真的有挂(有辅助挂方式)聚闲麻将能透视...
据报道开挂!旅游娱乐ai智能开... 据报道开挂!旅游娱乐ai智能开挂工具,旅游娱乐辅助工具演示(一直有挂教学)1、全新机制【旅游娱乐ai...
一分钟揭秘开挂!决胜朋来麻将a... 一分钟揭秘开挂!决胜朋来麻将ai智能透视辅助挂教程,决胜朋来麻将真是真的是有挂(有辅助挂总结)1、首...
如何分辨真伪透视!红牛ai智能... 如何分辨真伪透视!红牛ai智能透视攻略,红牛是不是有挂经验(真是有挂技术)1、操作简单,无需红牛手机...
2分钟细说辅助器!江湖大庆麻将... 2分钟细说辅助器!江湖大庆麻将ai智能透视辅助挂攻略,江湖大庆麻将竟然是真的有挂(有辅助挂头条)1、...
总算清楚透视挂!老夫子厅ai智... 总算清楚透视挂!老夫子厅ai智能透视挂技巧,老夫子厅怎么开挂课程(好像发现有挂)老夫子厅破解侠是真的...
解密关于辅助!菜鸟麻将ai智能... 解密关于辅助!菜鸟麻将ai智能透视辅助挂脚本,菜鸟麻将总是存在有挂(有辅助挂存在)1、用户打开应用后...