轻松理解Go函数传参内幕

2020-04-23  本文已影响0人  皇甫LG

一、内置类型作为参数传递

首先要明确一点:golang语言中是没有引用传递的

先上结论:
golang的所有内置类型()作为函数参数传递都是传值的方式,需要注意的是:array、slice和map作为函数参数时也是传值,但是如果对结构内元素进行的修改,修改的是原数据。如果是对其进行整体赋值,则不会修改原数据,相当于拷贝出一个新的临时变量。通过传递指针参数实现修改原数据。

Go内置基础类型如下

下面用程序来验证一下:

package main

import "fmt"

//TypeOfParams 解释函数各个参数到底是值传递还是引用?
func TypeOfParams(a int, b string, c []int, d [2]int, e map[int]string, f func(int, int), g chan int, h interface{}) {
    fmt.Printf("参数变量地址:a=%p, b=%p, c=%p, d=%p, e=%p, f=%p, g=%p, h=%p\n", &a, &b, &c, &d, &e, &f, &g, &h)

}

func main(){
    a := 10
    b := "abc"
    c := []int{1, 2, 3}
    d := [2]int{10, 20}
    e := make(map[int]string, 2)
    f := func(x, y int) {}
    g := make(chan int, 10)
    var h interface{}

    fmt.Printf("变量定义时:a=%p, b=%p, c=%p, d=%p, e=%p, f=%p, g=%p, h=%p\n", &a, &b, &c, &d, &e, &f, &g, &h)
    comm.TypeOfParams(a, b, c, d, e, f, g, h)
}

执行后:结果显示如下:


image

二、什么是值传递

函数传递的总是原参数的副本、一份拷贝,比如我们传递一个int类型的参数,传递的其实是这个int参数的一个副本。 如果传递的指针类型的参数,传递就是这个指针的一份拷贝,而不是这个指针指向的值。

看一个关于指针的例子:

package main

import "fmt"

func PointerParam(ip *int) {
    fmt.Printf("指针为函数参数的内存地址是:%p\n", &ip)
    *ip = 2
}

func main(){
    p := 1
    ip := &p
    fmt.Printf("原始指针的内存地址是: %p\n", &ip)
    comm.PointerParam(ip)
    fmt.Printf("int值被修改了,新值为: %d\n", p)
}

# 结果显示
原始指针的内存地址是: 0xc00000e060
指针为函数参数的内存地址是:0xc00000e068
int值被修改了,新值为: 2

结论:这个一个指针的拷贝,因为存放这个两个指针的内存地址是不同的,虽然指针指向的值相同,但却是两个不同的指针。

      0xc00000e060
      ------------>     +------------+
                        |   1(int)   |
                        |0xc0000b4048|
                        +------------+
                              |
                              |
                              |
                              |
      0xc00000e060            |             0xc00000e068
      ------------>     +------------+      <------------
                        |   2(int)   |
                        |0xc0000b4048|
                        +------------+

三、最终结论:

Go语言中所有的传参都是值传递(传值),都是一个副本,一个拷贝。因为拷贝的内容有时候是非引用类型(int、string、struct等这些),这样就在函数中就无法修改原内容数据;有的是引用类型(指针、map、slice、chan等这些),这样就可以修改原内容数据。

上一篇下一篇

猜你喜欢

热点阅读