golang中切片作为函数参数

随便写个获取二叉树后续遍历的值,结果让我很疑惑

初始方式

func postorderTraversal(root *TreeNode) []int {
    res:=make([]int,0)
    if root==nil{
        return res
    }
    dfs(root,res)
    return res
}

 func dfs(link *TreeNode,nums []int){
  if link==nil{
            return 
        }
        dfs(link.Left,nums)
        dfs(link.Right,nums)
        nums = append(nums,link.Val)
}

结果返回的res为空

不得已改写为以下方式,不传递切片进入函数,或者使用全局变量

unc postorderTraversal(root *TreeNode) []int {
    res:=make([]int,0)
    if root==nil{
        return res
    }

    var dfs func(link *TreeNode)
    dfs = func(link *TreeNode){
        if link==nil{
            return 
        }
        dfs(link.Left)
        dfs(link.Right)
        res = append(res,link.Val)
    }
    dfs(root)
    return res
}

不禁疑惑,不是说切片底层为数组指针吗,为什么传入函数之后append增加失败

更新 找到原因,因为函数拷贝的是Slice的结构,其实内部的和外部不是一个slice,虽然底层指针指向的可能是一个数组.

解释一下.

下面的代码

func main() {
 sl := make([]int, 0, 10)
 var appenFunc = func(s []int) {
  s = append(s, 10, 20, 30)
  fmt.Println(s)
 }
 fmt.Println(sl)
 appenFunc(sl)
 fmt.Println(sl)
 fmt.Println(sl[:10])
}

运行结果为
[]
[10 20 30]
[]
[10 20 30 0 0 0 0 0 0 0]

问题1: 为什么第二次打印sl是空数组?里面不是append了吗? 而且外层的slice是有足够容量不会扩容的.

因为切片结构是这样的

type SliceHeader struct {
 Data uintptr  //执行底层数组指针
 Len  int    // 长度
 Cap  int  //容量
}

传入函数中是对此结构的复制,函数内append改变的是函数内另外一个变量的Len, 外层切片的Len长度是没变化的,fmt打印的时候实际上是打印[0:len(sl)-1] 范围的元素.所以是空.

问题2: 为什么 fmt.Println(sl[:10]) 可以打印而且还有函数内append的元素?

因为切片的cap是10,函数内slice变量的Data结构和外部的Data指向相同的底层数组,里面append不会触发扩容,而且使用[m:n]方式访问切片右侧的范围其实是slice的Cap而不是Len
所以可以打印而且结果包含内部append的10,20,30

posted @ 2021-09-04 12:04  海拉尔  阅读(423)  评论(0编辑  收藏  举报