浅谈go二维数组的深复制

在go语言中,对于一个数组的赋值,和python一样,其实并没有开辟新空间,比如下面这行代码:

package main
import "fmt"
func main(){
    source:=[]int{1,2,3,4}
    dist:=[]int{}
    dist=source
    dist[0]=999 //对第二个数组进行修改

    fmt.Println(source)
}

打印的结果,为 [999,2,3,4]。这时候如果想对第二个数组进行修改,并且不影响原数组,也就是说,想让他们两个独立,这时候就需要关键字copy

package main
import "fmt"
func main(){
    source:=[]int{1,2,3,4}
    dist:=[]int{}
    copy(dist,source)
    dist[0]=999 //对第二个数组进行修改
    fmt.Println(source)
}

输出的结果为[1,2,3,4]。这是一维数组,很好写,也很简单。

二维数组的情况

二维数组的时候,情况变得复杂起来,比如你看下面的代码

package main
import "fmt"
func main(){
    source:=[][]int{{1,2,3,4},{5,6,7,8}}
    dist:=[][]int{}
    copy(dist,source)
    fmt.Println(dist)//直接对第二个数组进行输出
}

输出的结果:[] 为空,虽然没有报错,但是实际并没有成功,也就是说,copy只能复制一维的,那我们可以遍历二维数组,然后一个一个的进行复制,行不行?答案是:可以,但是对于写法有要求。先来一份正确的写法

package main
import "fmt"
func main(){
    source:=[][]int{{1,2,3,4},{5,6,7,8}}

    dist:=make([][]int,len(source))

    for i:= range source{
        dist[i]=make([]int,len(source[i]))
        copy(dist[i],source[i])
    }

    fmt.Println(dist)
}

上面的代码中,有两个make,都不可以省略。第一个make开辟数组的行数,(注:len(source)的值为2,因为source只有两行。)。第二个make开辟数组的空间,这个比较好理解。下面是错误的示范。

错误示范

  • 不写make可不可以?

    package main
    import "fmt"
    func main(){
      source:=[][]int{{1,2,3,4},{5,6,7,8}}
    
      dist:=[][]int{}
    
      for i:= range source{
          copy(dist[i],source[i])
      }
    
      fmt.Println(dist)
    }
    

    不行。

  • 写一个make可不可以

    package main
    import "fmt"
    func main(){
      source:=[][]int{{1,2,3,4},{5,6,7,8}}
    
      dist:=make([][]int,len(source))
    
      for i:= range source{
          //第二个不写
          //dist[i]=make([]int,len(source[i]))
          copy(dist[i],source[i])
      }
    
      fmt.Println(dist)
    }
    

    编译可通过,但是dist里面为空

    package main
    import "fmt"
    func main(){
      source:=[][]int{{1,2,3,4},{5,6,7,8}}
    
      dist:=[][]int{}
      for i:= range source{
          dist[i]=make([]int,len(source[i]))
          copy(dist[i],source[i])
      }
    
      fmt.Println(dist)
    }
    

    编译报错,数组越界,length 0 就越界