Golang - 指针与引用

Posted anthony-dong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Golang - 指针与引用相关的知识,希望对你有一定的参考价值。

? Golang有指针 , 那么一切数据都是值传递吗 ? 都需要用户进行指针传递吗, 其实不然, 对于Go语言, 虽然有指针, 但是其也有引用传递. 是不是很绕, 因为引用传递就是指针传递哇 . 我们继续解释.

概念

在Go语言中,对于布尔变量数值类型字符串类型数组 以及struct都是按照值传递的:值在传递给函数或者方法时会被复制一份,然后方法或函数使用的是复制的这份值,也就不会对原值产生什么影响。一般情况下,对于布尔变量或数值类型或字符串类型的按值传递是非常廉价的,Go语言编译器会在传递过程中进行安全优化。

对于大字符串是这样,对于数组进行值传递也是如此。为了解决可能产生的巨大代价,Go语言使用数组切片来代替数组的使用。传递一个切片的代价跟传递字符串差不多,无论该切片的长度或容量是多大。对切片进行复制修改操作也不会像字符串那样需要创建新的切片,因为切片是可变的,属于引用类型

因此以下就是重点 :

语言中的值传递类型有:基本数据类型,数组 , struct

特点:变量直接存储值,内存通常在栈中分配,栈在函数调用完会被释放 , 在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数 , 所以他最大的好处就是不怕多线程安全性问题. 但是浪费内存

Go语言中的引用类型有:映射(map),数组切片(slice),通道(chan),接口(interface) 与 函数(func)。

他的变量默认就是指针变量, 所以不需要做&取地址. 你要是花里胡哨我也无语.

特点:变量存储的是一个地址,这个地址存储最终的值。内存通常在堆上分配,通过GC回收。所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。引用注定多个线程中共享一个, 容易出现多线程问题,

就以引用传递和值传递区分 , 切记别被下面带绕了,这种话分析层面不同就不一样

其实在go语言中,只存在值传递,本质上,我们可以理解函数的传递都是值传递,只不过引用类型传递的是一个指向底层数据的指针,所以我们在操作的时候,可以修改共享的底层数据的值,进而影响到所有引用到这个共享底层数据的变量。

两大操作符

操作符& : 是返回该变量的内存地址。
操作符* :是返回该指针指向的变量的值,其实就是解除变量的指针引用,返回该变量的值.

空指针 :

当一个指针被定义后没有分配到任何变量时,它的值为 nil。
nil 指针也称为空指针。
nil在概念上和其它语言的null、None、nil、NULL一样,都指代零值或空值。

认识指针

指针这个玩意, Java里没有,其实Java里确实有指针,我们无时无刻在使用,下面我举一个例子

type People struct {
    name string
    sex  string
    age  int
}

func main() {
    
    var pp *People

    // 1. 返回一个对象
    person1 := People{"zhangsan", "man", 25}

    fmt.Println(person1)

    pp=&person1

    // 2. 直接实例化一个空对象 , 返回一个指针对象
    person2 := new(People)

    //
    pp=person2
    fmt.Println(*pp)

    // 2.返回一个指针对象
    person3 := &People{"wangwu", "man", 25}

    pp=person3

    fmt.Println(*person3)

    fmt.Println(*pp)
}

输出

{zhangsan man 25}
{  0}
{wangwu man 25}
{wangwu man 25}

这里告诉大家一个技巧就是 fmt.Println() 输出中如果首位是 & ,那么它一定是一个指针类型的数据 . 但是对于默认的引用对象,不一定了,,,

函数传参是值传递 - 但是引用类型是指针传递, 不需要用户写*申明指针类型

举个例子 我们拿数组为例子 , 举例指针的用处

func main() {

    // 申明数组类型
    arr := [3]int{1, 2, 3}

    // 原数组
    fmt.Printf("指针 : %p , 数据 : %v
", &arr,arr)

    // 地址传递
    printSlice(&arr)
    
    // 值传递
    printSlices(arr)

    // 原数组
    fmt.Printf("指针 : %p , 数据 : %v
", &arr,arr)

}

func printSlice(arr *[3]int) {
    // 修改数据
    arr[0] = 5
    fmt.Printf("指针 : %p , 数据 : %v
", arr, *arr)
}
func printSlices(arr [3]int) {
    // 修改数据
    arr[0] = 4
    fmt.Printf("指针 : %p , 数据 : %v
", &arr, arr)
}

输出

指针 : 0xc000052140 , 数据 : [1 2 3]
指针 : 0xc000052140 , 数据 : [5 2 3]
指针 : 0xc0000521c0 , 数据 : [4 2 3]
指针 : 0xc000052140 , 数据 : [5 2 3]

参考 https://www.cnblogs.com/52php/p/6727082.html

以上是关于Golang - 指针与引用的主要内容,如果未能解决你的问题,请参考以下文章

谈谈golang中的引用类型与地址分配

golang有没有必要传递map指针

golang - mysql 恐慌:运行时错误:无效的内存地址或 nil 指针取消引用

使用 Kotlin 在片段中引用 RecyclerView 时出现空指针错误

sql golang查询时,无效的内存地址或nil指针取消引用。

Golang查缺补漏