本文正在参加 「金石方案 . 瓜分6万现金大奖」

本次文章主要是来聊聊关于切片传值需求留意的问题,假如不小心,则很容易引发线上问题,假如不行了解,可能会呈现奇奇怪怪的现象

问题状况:

小 A 负责一个模块功用的完成,在调试代码的时候可能不仔细,布置到线上环境时发现在现有战略列表上追加新的战略时,总是无法收效,这是为什么呢?

清查代码后发现问题出在关于切片的运用上出了认知误差,小 A 以为 golang 中,传切片就是传引证,因而写出了这样的代码片段

func xxxFunc(sli []int ,newSli []int) {
   // ... 省掉部分代码
   sli = append(sli, newSli...)
   // ... 省掉部分代码
   return 
}

想表达的意思是:

传入的 sli 切片归于旧切片,期望在 sli 切片上追加 newSli 中的元素,终究期望得到的 sli 里边是包含 newSli 元素的

可是,关于 Golang 中切片 slice 有一定了解的 xdm 就很清楚,这样写其实并没有什么实践作用,在 Golang 中传参都是传值而不是传地址

因而此处传入的 sli 切片,也仅仅是一个复制罢了,在 xxxFunc 函数中的 sli 切片被修正了,实践上是不会影响函数外部的 sli 的

那么关于切片此处做几个阐述

首先着重几点关于切片的留意事项

  1. Golang 中的函数参数,都是传值,不是传地址
  1. 关于切片本身的底层数据结构,咱们能够经过索引的方法拿到底层数组的地址,并修正其地址上的值,例如 sli[2] = "hello",这是能够直接修正
  1. 假如传入的切片,期望实参也能够被改动的话,那么就需求想办法修正切片的底层数组

    1. 经过传切片的地址,也就是传指针的方法
    2. 在函数中,去索引切片的底层数组地址,进行修正数据

事例 1 遍历的时候修正

经过 value 修正切片值 – 不靠谱

咱们给出一个切片 var mySlice = []int{7, 8, 9} ,并编写如下几个函数来检查是否会对原有切片数据有影响


func main() {
   log.SetFlags(log.Lshortfile)
   var mySlice = []int{7, 8, 9}
   log.Printf("mySlice == %+v", mySlice)
   log.Println("---------------------------------------------")
   mySliceDemo := testDemo(mySlice)
   log.Printf("mySlice == %+v ,mySliceDemo == %+v", mySlice, mySliceDemo)
   log.Printf("mySlice == %p ,mySliceDemo == %p", &mySlice, &mySliceDemo)
}
func testDemo(sli []int) []int {
   for _, value := range sli {
      value *= 2
   }
   return sli
}

给 testDemo 传入 mySlice 切片,在函数内部经过 for…range 的方法去修正切片内元素的值,可是代码中的 value 依然是一个复制,他并不会真的对外部的 mySlice 有任何影响,成果天然是这样的

【切片】基础不扎实引发的问题

能够经过修正切片索引上的值

当然假如咱们这样写,去找到索引对应的底层数组的地址,再修正其地址上的值,是可行的

func testDemo2(sli []int) []int {
   for index, _ := range sli {
      sli[index] *= 2
   }
   return sli
}

【切片】基础不扎实引发的问题

天然经过指针的方法依然能够

传入的这个指针,实践上也是一个复制,只不过复制的是这个指针,也就是指针本身的地址不相同,可是他们指向的底层数组是相同的,因而能够直接修正

这种修正的方法,也是去修正地址上的值,因而有用

func testDemo3(sli *[]int)  {
   for index, _ := range *sli {
      (*sli)[index] *= 2
   }
   return
}

成果天然 ok,原有 mySlice 的地址也是没有发生改变的,仅仅值发生了改变

【切片】基础不扎实引发的问题

事例 2 运用 append 会有什么不同

那么假如是在子函数里边运用 append 追加数据,是否会有不同的效果?

func appendDemo(sli []int) []int {
   sli = append(sli, 999)
   return sli
}

【切片】基础不扎实引发的问题

实践上,此处传入的依然是 mySlice 的复制,appendDemo 中运用 append,也是根据复制后的值来进行数据追加

哪怕是遇到切片扩容的状况,也仅仅是关于函数内的复制副本来进行扩容和改变,例如这样

func appendDemo3(sli []int)[]int{
   sli = append(sli, []int{3,4}...)
   return sli
}

【切片】基础不扎实引发的问题

传入切片的地址

在运用 append 的状况, 向函数参数中传入切片的指针,此处关于函数来说,依然是一个副本,只不过这个副本是指针,指向的底层数组依然是和 mySlice 是相同的,因而能够经过这个复制的指针去修正实践底层数组的值

func appendDemo2(sli *[]int){
   *sli = append(*sli, []int{1000,10001}...)
   return
}

【切片】基础不扎实引发的问题

能够看到运用指针的方法,处理起来还是妥妥的,在 appendDemo2 中实践修正了 mySlice 的值,且也是咱们所期望的

至此,关于文章最初问题的解决方法,xdm 心中都有数了吧,那就不能再犯了吧,期望能够给你带来帮助

感谢阅读,欢迎沟通,点个赞,重视一波 再走吧

欢迎点赞,重视,保藏

朋友们,你的支持和鼓舞,是我坚持分享,进步质量的动力

【切片】基础不扎实引发的问题

技术是敞开的,咱们的心态,更应是敞开的。拥抱改变,向阳而生,努力向前行。

我是阿兵云原生,欢迎点赞重视保藏,下次见~

文中提到的技术点,感兴趣的能够检查这些文章:

  • 你以为传切片就是传引证了吗?
  • 你真的知道 GO 中 nil 代表什么吗?
  • GO 中 slice 的完成原理
  • 微服务线上问题排查困难?不知道问题出在哪一环?那是你还不会分布式链路追寻
  • k8s 服务升级为啥 pod 会布置到咱们不期望的节点上??看来你还不懂污点和容忍度