1、在Go语言中,值类型和引用类型有以下特点:
栈上分配
堆上分配
- 严格来说,Go 语言没有引用类型。
- 但是我们可以把 map、chan、函数、接口、slice 切片, 称为引用类型,这样便于理解。
- 指针类型也可以理解为是一种引用类型。
上面我们提到了堆、栈,这里简单介绍下
栈堆
值类型和指针类型参数示例:
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{ //省略无关代码 } 复制代码
chanchannel 本质上也是个指针,来看源码:
func makechan(t *chantype, size int64) *hchan { //省略无关代码 } 复制代码
可以看到创建的 chan 其实是个 *hchan,所以它在参数传递中也和 map 一样。
类型的零值声明makenew函数
类型 | 零值 |
数值类型(int、float等) | 0 |
bool | false |
string | ""(空字符串) |
struct | 内部字段的零值 |
slice | nil |
map | nil |
指针 | nil |
函数 | nil |
chan | nil |
interface | nil |
在 Go 语言中,函数的参数传递只有值传递,而且传递的实参都是原始数据的一份拷贝。如果拷贝的内容是值类型的,那么在函数中就无法修改原始数据;如果拷贝的内容是指针(或者可以理解为引用类型 map、chan 等),那么就可以在函数中修改原始数据。