So I am back with more beginner questions that I can not seem to wrap my head around. I was experimenting with the following code.
func main() {
start := time.Now()
var powers []*big.Int
for i := 1; i < 1000; i++ {
I := big.NewInt(int64(i))
I.Mul(I, I)
powers = append(powers, I)
}
fmt.Println(powers)
fmt.Println(time.Since(start))
start = time.Now()
var seqDiffs []*big.Int
diff := new(big.Int)
for i, v := range powers {
if i == len(powers)-2 {
break
}
diff = v.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, diff)
}
fmt.Println(seqDiffs)
fmt.Println(time.Since(start))
}
my intention was to assign the result of Sub() to diff in the following way
diff.Sub(powers[i+1], v)
however this results in seqDiffs's value being 1995 (the correct last value) repeated over and over. I know that this is likely because seqDiffs is just a list of pointers to the same memory address but what I dont understand is why the following works just fine
v.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, v)
this results in seqDiffs being a list of all the odd numbers from 3 to 1995 which is correct but isn't this essentially still a list of pointers to the same memory address as well? Also why is the following correct when it should also result in seqDiffs being a list of pointers to the same memory address as well?
diff = v.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, diff)
also I tried to do it the following way
diff := new(*big.Int)
for i, v := range powers {
if i == len(powers)-2 {
break
}
diff.Sub(powers[i+1], v)
seqDiffs = append(seqDiffs, diff)
}
but received these errors from the ide:
*./sequentialPowers.go:26: calling method Sub with receiver diff (type **big.Int) requires explicit dereference
./sequentialPowers.go:27: cannot use diff (type **big.Int) as type *big.Int in append*
How would I make an "explicit" dereference?
When debugging issues with pointers in Go, one way to understand what is going on is use fmt.Printf
using %p
to print the memory address of variables of interest.
In regards to your first question as to why when appending the results of diff.Sub(powers[i+1], v)
to your slice of *big.Int
results in a slice where every index is the same value - you are updating the value at the memory address diff
is assigned to and appending a copy of that pointer to the slice. Thus all values in the slice are pointers to the same value.
Printing the memory address of diff
will show this to be the case. After populating your slice - doing something like the following:
for _, val := range seqDiffs {
fmt.Printf("%p
", val) // when i ran this - it printed 0xc4200b7d40 every iteration
}
In your second example, the the value v
is pointer to a big.Int
at a different address. You are assigning the the result of v.Sub(..)
to diff
, which updates the underlying address diff is pointing to. So when you append diff
to your slice, you are appending a copy of of a pointer at a unique address. Using fmt.Printf
you can see this like so -
var seqDiffs []*big.Int
diff := new(big.Int)
for i, v := range powers {
if i == len(powers)-2 {
break
}
diff = v.Sub(powers[i+1], v)
fmt.Printf("%p
", diff) // 1st iteration 0xc4200109e0, 2nd 0xc420010a00, 3rd 0xc420010a20, etc
seqDiffs = append(seqDiffs, diff)
}
Regarding your second question - using the new
keyword in Go allocates memory of the specified type but does not initialize it (check the docs). A call to new
in your case allocates a type of pointer to a pointer to a big.Int
(**big.Int
), thus the compiler error saying you cannot use this type in your call to append
.
To explicitly dereference diff
in order to call the Sub
on it, you would have to modify your code to the following:
(*diff).Sub(powers[i+1], v)
In Go, a selector expression dereferences pointers to structs for you, but in this case you are calling a method on a pointer to a pointer, thus you have to explicitly dereference it.
A very informative read on calling methods on structs (selector expressions) in Go can be found here
And to add it to the slice
seqDiffs = append(seqDiffs, *diff)