处理切片参数的必要操作#

举报
码乐 发表于 2025/04/24 09:58:26 2025/04/24
【摘要】 1 简介go语言中 所有对象都是 pass by value, 那么go语言变量为何还有 值传递和 引用传递的区别?当有人说 “go的所有变量传递都是值传递”,这句话是真的其中也包含了一些容易混淆的细节。 2. Go 中“所有传参都是值传递”无论传递什么类型的变量(包括指针、slice、map、chan、interface 等),它们都是 值传递。也就是说,当你调用一个函数并传递一个变量...

1 简介

go语言中 所有对象都是 pass by value, 那么go语言变量为何还有 值传递和 引用传递的区别?
当有人说 “go的所有变量传递都是值传递”,这句话是真的其中也包含了一些容易混淆的细节。

2. Go 中“所有传参都是值传递”

无论传递什么类型的变量(包括指针、slice、map、chan、interface 等),它们都是 值传递。

也就是说,当你调用一个函数并传递一个变量进去时,函数接收到的是该变量的副本(拷贝),而不是变量本身。

3. 那“引用传递”的说法是怎么来的?

所谓“引用传递”,其实是指你传递的是一个 包含指针的值。虽然值本身是被拷贝的,但它 指向了原始的数据,所以你可以通过这个拷贝来修改原始数据的内容。

  • 举个例子说明

值传递(传普通类型)

  func changeValue(x int) {
      x = 100
  }

  func main() {
      a := 10
      changeValue(a)
      fmt.Println(a) // 输出仍然是 10
  }

解释:a 被复制了一份传给 x,函数中修改的是副本,不影响原始变量。

  • 引用“语义”的值传递(传指针)

      func changePointer(x *int) {
          *x = 100
      }
    
      func main() {
          a := 10
          changePointer(&a)
          fmt.Println(a) // 输出 100
      }
    

解释:你传的是一个指针(地址),虽然这个指针也是复制的,但它指向原始变量 a,所以可以修改它的值。

4 传 slice的解决办法(底层是引用类型)

切片 当它传递时,它与指向底层数组的指针一起传递,切片值仅包含指向实际存储元素的数组的指针。

    func changeSlice(s []int) {
        s[0] = 100
    }

    func main() {
        arr := []int{1, 2, 3}
        changeSlice(arr)
        fmt.Println(arr) // 输出 [100 2 3]
    }

虽然 arr 是通过值传递传进去的,但是 slice 本质上是一个结构体,包含一个指向底层数组的指针。这个结构体被复制了,但它仍指向原始数组。

slice 值不包括其元素(与数组不同)。slice值是一个 header ,描述后备数组的连续部分,当您将 slice 传递给函数时,将从此 Headers 中制作一个副本,包括指针,它将指向相同的后备数组。

修改 slice 的元素意味着修改 backing 数组的元素,因此共享同一 backing 数组的所有 slice 都将 “观察” 更改。

处理传递给函数的切片的最佳方法(如果切片的元素作到函数中,并且我们不希望这反映在 elements 内存块中),
则使用以下方式复制它们:copy(new_slice, *old_slice)

func changeSlice(old_slice []int) []int {
	var new_slice = make([]int, len(*old_slice))

	copy(new_slice, *old_slice)
		for index, _ := range s {
	        s[index] = 1011
	    }
    return s 
	}

切片是指向底层数组的指针。指针被复制,但它仍然指向相同的底层数组。
包含 slice 元素的内存块由 “reference” 传递。
包含容量、元素数量和指向元素的指针的切片信息三元组按 value 传递。

5 小结:

		类型					值是否被复制			能否修改原数据			原因
		基本类型(int、bool)	✅ 是副本			❌ 不行				函数内是副本
		指针	✅ 				是指针副本	✅ 可以修改原数据			指针指向原始数据
		slice/map/channel	✅ 是结构体副本	✅ 可以修改原数据		内部默认有底层数据的指针
		struct				✅ 整体被复制		❌/✅ 取决于字段内容	  若有指针字段,可能可以改

“引用传递”的说法是为了便于理解,特别是与 Java/C++ 等语言对比的时候。在 Go 中传指针、slice、map 时的行为**“看起来像引用传递”**,因为你修改了函数外的数据。但从语言语义上说,这仍然是 值传递 —— 只不过值中包含的是“引用”

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。