golang读取文件的几种方法?文章快查Golang越学越难之引用陷阱(一),现在小编就来说说关于golang读取文件的几种方法?下面内容希望能帮助到你,我们来一起看看吧!

golang读取文件的几种方法(Golang越学越难之引用陷阱)

golang读取文件的几种方法

文章快查

Golang越学越难之引用陷阱(一)

前言

看过上篇文章的同学可以得知,在同定义域内调用append进行元素追加,若没有正确的对象进行接收,是存在引用风险的。

本文将结合实际案例,继续探究以Slice为典型引用类型代表的陷阱。

问题一

在日常研发工作中,大家经常会写出这么一段代码:

func main() {
      //创建一个长度和容量均为3的切片
      arr := []int{1,2,3}
      fmt.Println(arr) // [1 2 3]
      //-------
      addNum(arr)      
      //-------
      fmt.Println(arr) // [1,2,3]
}

func addNum(sli []int){
      //使用appedn添加"4"
      sli = append(sli,  4)
      fmt.Println(sli) // [1,2,3,4]
}

有同学可能会感到疑惑,为什么已经使用了sli对append返回的切片进行接收,在main函数中还是没能打印出来?

那么我们接着看:

func main() {
      arr := []int{1,2,3}
      fmt.Printf("%p\n",arr) //0xc000014150
      //-------
      addNum(arr)
      //-------
      fmt.Printf("%p\n",arr) //0xc000014150
}

func addNum(sli []int){
      sli = append(sli,  4)
      fmt.Printf("%p\n",sli) //0xc00000c360
}

是不是有种恍然大悟的感觉。从输出结果可知,拷贝切片指针发生改变,而原指针并没有变化。

问题二

此时创建一个长度为3,容量为4的切片,并再次使用append方法在函数中对切片进行添加操作。

func main() {
   arr := make([]int,3,4)//创建一个长度为3,容量为4的切片
   fmt.Printf("%p\n",arr)  //0xc000012200
   // -----
   addNum(arr)
   // -----
   fmt.Printf("%p\n",arr)  //0xc000012200
}

func addNum(sli []int){
   sli = append(sli,  4)
   fmt.Printf("%p\n", sli) //0xc000012200
}

从结果可以看出,因为初始时,已经设置了切片的容量为4,所以拷贝切片并没有因为扩容指向新的数组。

那此时原切片是否会发生改变?

func main() {
      arr := make([]int, 3, 4) //创建一个长度为3,容量为4的切片
      fmt.Printf("%p\n", arr) //0xc000012200
      fmt.Println(arr)        //[0 0 0]
      // -------
      addNum(arr)
      // -------
      fmt.Printf("%p\n", arr) //0xc000012200
      fmt.Println(arr)        //[0 0 0]
}

func addNum(sli []int) {
      sli = append(sli, 4)
      fmt.Printf("%p\n", sli) //0xc000012200
      fmt.Println(sli)        //[0 0 0 4]
}

从代码运行结果可以看出,原切片并没有发生改变。

因为,虽然原切片的底层数组发生了变化,但长度Len没有发生变化,因此原切片的值仍然不变。

看官方怎么说

In a function call, the function value and arguments are evaluated in the usual order. After they are evaluated, the parameters of the call are passed by value to the function and the called function begins execution.

官方很隐晦的给出了Golang中并没有引用传递的概念,Golang是不存在引用传递的。

但网上有很多的说法,最多的是slice,map和chan作为参数传递到函数中时是传的引用,其实这个说法不准确,我们不能单纯因为函数内部的修改可以反馈到外面就认为是传递的引用。

小结

(1)当未扩容时,原切片底层数组改变,但是在原切片结构体中Len参数是值传递,所以不会影响外部切片,故在内部修改而外部不可见;

(2)当发生扩容时,生成新切片对象,切片地址改变,故而外部切片地址不变(旧切片),故而也不可见。

(3) Go语言中不存在引用类型。

,