乐趣区

关于golang:Go语言参数传递中值引用及指针之间的区别

值类型、援用类型

1、在 Go 语言中,值类型和援用类型有以下特点:
a、值类型 : 根本数据类型,int,float,bool,string, 以及数组和 struct
特点:变量间接存储值,内存通常在 栈上调配,栈在函数调用完会被开释

b、援用类型 :指针,slice,map,chan,interface 等都是援用类型
特点:变量存储的是一个地址,这个地址存储最终的值。内存通常在 堆上调配,通过 GC 回收。

  • 严格来说,Go 语言没有援用类型。
  • 然而咱们能够把 map、chan、函数、接口、slice 切片,称为援用类型,这样便于了解。
  • 指针类型也能够了解为是一种援用类型。

下面咱们提到了堆、栈,这里简略介绍下

内存调配中的堆和栈:

  • (操作系统):由操作系统主动调配开释,寄存函数的参数值,局部变量的值等。其操作形式相似于数据结构中的栈。
  • (操作系统):个别由程序员调配开释,若程序员不开释,程序完结时可能由 OS 回收,调配形式倒是相似于链表。

值类型和指针类型参数示例:

package main

import "fmt"

func main() {
    name := "无尘"
    modify1(name)
    fmt.Println("name 的值为:", name)
    modify2(&name)
    fmt.Println("name 的值为:", name)
}

func modify1(name string) { // 值类型
    name = "wucs"
} 
func modify2(name *string) { // 指针类型
    *name = "wucs"
}
// 运行后果://name 的值为: 无尘
//name 的值为: wucs

援用类型

map
以 map 类型为参数示例:

package main

import "fmt"

func main() {m:=make(map[string]int)
    m["无尘"] = 18
    fmt.Println("无尘的年龄为",m["无尘"])
    modify(m)
    fmt.Println("无尘的年龄为",m["无尘"])
}
func modify(p map[string]int)  {p["无尘"] =20
}
// 运行后果:// 无尘的年龄为 18
// 无尘的年龄为 20
  • 咱们看到,函数 modify 的参数类型为 map , 数据依然批改胜利了。
  • 其实,在创立 map 的时候,最终调用的是 runtime.makemap 函数,makemap 函数返回的是一个 hmap 类型,也就是说返回的是一个指针,所以咱们创立的 map 其实就是一个 hmap。
  • 因为 map 实质上就是个指针,所以通过 map 类型的参数能够批改原始数据。

    // makemap implements Go map creation for make(map[k]v, hint).
    func makemap(t *maptype, hint int, h *hmap) *hmap{// 省略无关代码}

chan
channel 实质上也是个指针,来看源码:

func makechan(t *chantype, size int64) *hchan {// 省略无关代码}

能够看到创立的 chan 其实是个 *hchan,所以它在参数传递中也和 map 一样。

类型的零值

  1. 在 Go 语言中,定义变量能够通过 申明 或者通过 makenew 函数,区别是 make 和 new 函数属于显示申明并初始化。
  2. 如果咱们申明的变量没有显示的申明初始化,那么该变量的默认值就是对于类型的零值。
类型 零值
数值类型(int、float 等) 0
bool false
string “”(空字符串)
struct 外部字段的零值
slice nil
map nil
指针 nil
函数 nil
chan nil
interface nil

在 Go 语言中,函数的参数传递只有值传递,而且传递的实参都是原始数据的一份拷贝。如果拷贝的内容是值类型的,那么在函数中就无奈批改原始数据;如果拷贝的内容是指针(或者能够了解为援用类型 map、chan 等),那么就能够在函数中批改原始数据。

退出移动版