-2

I have been playing around with methods in Go by building a small linear algebra library, but I have run into a problem with the following piece of code:

package main

import (
    "fmt"
)

type Matrix struct {
    mat    []float64
    nR, nC int
}

func (m Matrix) String() string { ... }

// EmptyMatrix initializes a nR*nC matrix to 0
func EmptyMatrix(nR, nC int) Matrix { ... }

// BuildMatrix creates a matrix build by its rows, and returns a Matrix
func BuildMatrix(rows ...[]float64) Matrix { ... }

// Set sets the value of mat[i,j] to val
func (m *Matrix) Set(i, j int, val float64) {
    if (i < m.nR) && (j < m.nC) {
        m.mat[i*m.nC+j] = val
    } else {
        panic(fmt.Sprintf("Index (%d,%d) out of range (0:%d,0:%d)",
                          i, j, m.nR, m.nC))
    }
}

func main() {
    matA := matrix.BuildMatrix([]float64{2, 3}, []float64{4, -5})
    matB := matA
    fmt.Println(matA)
    matB.Set(1,1,2)
    fmt.Println(matA)
    fmt.Printf("%p\n%p\n",&matA,&matB)
}

When ran, this is the output:

[ [ 2.00 3.00 ]
  [ 4.00 -5.00 ] ]
[ [ 2.00 3.00 ]
  [ 4.00 2.00 ] ]
0xc04207c060
0xc04207c090

If I change a value in matB, the change is mirrored in matA, which is not what I want. In Python I would have made a deep copy of matA to start with, but I haven't found any standard Go implementation of Python's copy.deepcopy()function. How should I go about solving it?

TESTED SOLUTIONS:

  1. Matrix.mat is indeed a slice, and I should be copying with copy(matB.mat, matA.mat. However, this is not the only problem, since it's still doing the same thing.
mariohm1311
  • 101
  • 2
  • you mean `copy()`? You have a single slice, just need to copy it. – JimB Jan 31 '18 at 19:29
  • It's not a slice, it's a struct. Forgot to include the BuildMatrix function, but basically it creates a Matrix with the given rows. – mariohm1311 Jan 31 '18 at 19:34
  • `BuildMatrix` is not shown in the code, but assuming it returns a pointer, then `matA` and `matB` are both pointers to the same object. It's not so much that the changes are "mirrored" as that they're two references to the exact same object. – Adrian Jan 31 '18 at 19:34
  • Edited the code to include the header of the function. `BuildMatrix` does not return a pointer. In fact, `matA` and `matB` are in different memory locations. – mariohm1311 Jan 31 '18 at 19:37
  • @mariohm1311: `Matrix.mat` is a slice, and you need to copy that slice. – JimB Jan 31 '18 at 19:48
  • That's not the solution apparently, just tested it. – mariohm1311 Jan 31 '18 at 20:08
  • @mariohm1311: what isn't the solution? The values are changing in both because it's the same backing array for the slice. If copying the slice still doesn't work, you need to provide a [mcve] showing the problem. – JimB Jan 31 '18 at 20:35
  • Sorry about that, you're right. – mariohm1311 Jan 31 '18 at 20:56

1 Answers1

0

matA.mat and matB.mat both point to the same location.

A slice is a descriptor of an array segment. It consists of a pointer to the array, the length of the segment, and its capacity (the maximum length of the segment).

https://blog.golang.org/go-slices-usage-and-internals

When you copy the struct, the copied struct contains a copy of the pointer (which points to the same array segment).

See https://play.golang.org/p/KUWq-dnGMRl

You need to do

matB.mat = make([]float64, len(matA.mat))
copy(matB.mat, matA.mat)

https://play.golang.org/p/ZlmFT8toj6A

Community
  • 1
  • 1
dave
  • 62,300
  • 5
  • 72
  • 93