如何在Golang中理解值类型和引用类型区别_函数传参示例

15次阅读

go语言中所有参数均为值传递,但int值类型复制全部内容,slice等引用类型仅复制header(含指针),故修改元素影响原变量;需改原始值必须传指针。

如何在Golang中理解值类型和引用类型区别_函数传参示例

Go语言中没有传统意义上的“引用类型”,所有参数都是值传递,但不同数据类型的底层行为差异会让开发者产生“值类型”和“引用类型”的直观感受。关键在于:传递的是变量的副本,而这个副本的内容决定了它是“独立拷贝”还是“指向同一底层资源”的句柄。

哪些是常说的“值类型”

包括 intfloat64boolStringStructArray 等。它们在赋值或传参时,整个数据内容被完整复制一份。

  • 修改函数内参数,不会影响原始变量
  • 注意:string 虽然不可变且底层含指针,但 Go 把它设计为值语义——每次赋值都复制 header(含指针和长度),但不复制底层数组;修改 string 实际是创建新 string,所以仍符合“值类型”行为直觉

哪些常被当作“引用类型”使用

包括 slicemapchannelfuncInterface{}。它们本质是**头信息结构体(header)**,内部包含指针、长度、容量等字段,传参时只复制这个 header,而非底层数据。

  • 修改 slice 元素(如 s[0] = 10)会影响原 slice,因为 header 中的指针指向同一底层数组
  • 但对 slice 本身重新赋值(如 s = append(s, 1))可能扩容并生成新底层数组,此时原 slice 不受影响——因为只是改了副本 header 的指针,没动原来的
  • map 和 channel 同理:增删元素会影响原变量;但用 make 重新赋值给参数变量,不影响外部

指针类型:真正可控的“引用”方式

如果你需要在函数内修改原始变量的值(比如改变 int 变量内容、替换 struct 字段、或让 slice 指向新数组),必须显式传入指针。

立即学习go语言免费学习笔记(深入)”;

  • 声明形参*T,调用时传 &x
  • 函数内通过 *p = ... 修改原始内存位置的值
  • 这是唯一能真正改变调用方变量内容的方式(除上述 header 类型的间接修改外)

一个对比示例

以下代码清晰展示差异:

func modifyInt(x int) { x = 999 } func modifySlice(s []int) { s[0] = 999; s = append(s, 123) } func modifySlicePtr(s *[]int) { *s = append(*s, 456) }  func main() {     a := 10     modifyInt(a)     fmt.Println(a) // 输出 10 —— 值类型,未变      s := []int{1, 2, 3}     modifySlice(s)     fmt.Println(s) // 输出 [999 2 3] —— 元素被改,但 append 没影响原 s      modifySlicePtr(&s)     fmt.Println(s) // 输出 [999 2 3 456] —— 通过指针成功追加 }

text=ZqhQzanResources