当前位置: 代码网 > it编程>前端脚本>Golang > go中值传递和指针传递的使用

go中值传递和指针传递的使用

2024年11月03日 Golang 我要评论
1、& 和 *&后跟一个变量名,得到的是这个变量的内存地址*int类型的变量,代表这个变量里存的值是int类型的变量的内存地址数据类型的指针类型,即在其前面加*号指针就是内存地址pac

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数据时,数据库中默认值不对的时候:

在这里插入图片描述

到此这篇关于go中值传递和指针传递的使用的文章就介绍到这了,更多相关go 值传递和指针传递内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

相关文章:

  • Golang Map简介以及底层原理

    Golang Map简介以及底层原理

    map 简介在go语言中提供了map数据结构来存储键值对数据。map的数据类型为map[k]v,其中k为键的类型,v为值的类型。map的键类型必须支持==操作符... [阅读全文]
  • Go语言中的网络编程实现方式

    Go语言中的网络编程实现方式

    引言go语言作为一种简洁而强大的编程语言,在网络编程方面表现尤为出色。其内置的net包提供了丰富的网络i/o基础设施,支持tcp、udp协议,以及dns解析等功... [阅读全文]
  • Go语言的io输入输出流方式

    Go语言的io输入输出流方式

    go语言的io输入输出流go语言的输入输出流不如其他语言那么直观,由于是通过实现接口方法的隐式继承所以比较抽象,今天具体介绍一下go语言的输入输出流。go语言输... [阅读全文]
  • Go语言Seeker接口与文件断点续传实战教程

    seeker接口在现代软件开发中,高效的输入输出(i/o)操作是提高程序性能的关键之一。特别是在处理大量数据时,i/o操作的效率直接影响到应用程序的响应速度和用户体验。go语言标准…

    2024年11月03日 前端脚本
  • Go语言标准错误error全面解析

    Go语言标准错误error全面解析

    错误类型errorstring错误是程序中处理逻辑和系统稳定新的重要组成部分。在go语言中内置错误如下:// the error built-in interf... [阅读全文]
  • Go语言内建函数len的使用

    Go语言内建函数len的使用

    在 go 语言中,len 是一个非常常用的内建函数,它用于获取各种数据类型的长度或大小。掌握 len 的使用方法,可以帮助我们更高效地处理数据结构。本文将详细介... [阅读全文]

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com