why the value of an array could be changed by another variable - go

the array in golang is value type. In my understanding, value type save the value, but not a memory address. So the following code, variable arr shouldn't be changed. but it no. I want know why
func main() {
arr := []int{0,0,0}
arr2 := arr
arr[1] = 1
fmt.Println(arr, arr2)
// output [0 1 0] [0 1 0]
// output in thought [0 0 0] [0 1 0]
}
maybe this is a basic question. But I found some article. they all just said which are reference types and value types in golang. But it couldn't help me to solve my problem.

You are using a slice, not an array. In your program, both arr and arr2 are slices pointing to the same array. Change it so that:
arr := [3]int{0,0,0}
Then, arr is an array, and it works as you expect.

Related

Trying to initialize 2D slice, but the element reference changes all the rows in the slice [duplicate]

This question already has answers here:
What is a concise way to create a 2D slice in Go?
(4 answers)
Closed 2 years ago.
I created a 2D slice using the below code. Say I created [3]3] slice -- [[1 2 3],[4 5 6][7 8 9]]
But if I update the slice say s[1][1]=99 all changes --> [1 99 3], [4 99 6], [7 99 9]]
However, the second slice I have initialized below with variable cost does behave correctly. Not sure what is wrong:
func CreateSparseM() *SparseM{
var m,n,nz int
fmt.Println("Enter the row count of matrix ")
fmt.Scan(&m)
fmt.Println("Enter the column count of matrix ")
fmt.Scan(&n)
fmt.Println("Enter the count of Non Zero elements in the matrix ")
fmt.Scan(&nz)
r:=make([][]int,m)
c:=make([]int,n)
for i:=0;i<m;i++{
r[i] = c
}
fmt.Println(" r ", r)
r[1][1] = 99
fmt.Println(r[1][1])
fmt.Println(r[0][1])
//enter the non-zero elements
var row,col,elem int
for i:=0;i<nz;i++{
fmt.Println("Enter row ")
fmt.Scan(&row)
fmt.Println("Enter col ")
fmt.Scan(&col)
fmt.Println("Enter element ")
fmt.Scan(&elem)
r[row][col] = elem
}
fmt.Println(r)
cost:= [][]int{ {1,1,2,2,3,4,4,5,5},
{2,6,3,7,4,5,7,6,7},
{25,5,12,10,8,16,14,20,18}}
fmt.Println(cost)
cost[1][2]= 777
fmt.Println(cost)
sparseM := &SparseM{m,n,nz,r}
return sparseM
}
A slice contains a reference to an array, the capacity, and the length of the slice. So the following code:
r:=make([][]int,m)
c:=make([]int,n)
for i:=0;i<m;i++{
r[i] = c
}
sets all of r[i] to the same slice c. That is, all r[i] share the same backing array. So if you set r[i][j]=x, you set j'th element of all slices r[i] to x.
The slice you initialized using a literal has three distinct slices, so it does not behave like this.
If you do:
for i:=0;i<m;i++{
r[i] = make([]int,n)
}
then you'll have distinct slices for the first case as well.

golang combination generation made an error

I'm dealing with a programming problem
Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.
and with input n = 5, k = 4, the output should be [[1,2,3,4],[1,2,3,5],[1,2,4,5],[1,3,4,5],[2,3,4,5]], the following is my golang solution
func combine(n int, k int) [][]int {
result := [][]int{}
comb := []int{}
subcom(0, k, n, &comb, &result)
return result
}
func subcom(s, k, n int, comb *[]int, result *[][]int) {
if k > 0 {
for i := s + 1; i <= n-k+1; i++ {
c := append(*comb, i)
subcom(i, k-1, n, &c, result)
}
} else {
*result = append(*result, *comb)
}
}
I think my solution is right, but it return [[1 2 3 5] [1 2 3 5] [1 2 4 5] [1 3 4 5] [2 3 4 5]].
After debugging, I found [1 2 3 4] was added to the result slice at the beginning, but later changed to [1 2 3 5], resulting in the repetition of two [1 2 3 5]s. But I can't figure out what's wrong here.
This is a common mistake when using append.
When your code runs c:=append(*comb,i), it tries to first use the allocated memory in the underlying array to add a new item and only create a new slice when it failed to do so. This is what changes the [1 2 3 4] to [1 2 3 5] - because they share the same underlying memory.
To fix this, copy when you want to append into result:
now := make([]int,len(*comb))
copy(now,*comb)
*result = append(*result,now)
Or use a shortcut of copying:
*result = append(*result, append([]int{},*comb...))
Update:
To understand what I mean by underlying memory, one should understandd the internal model of Go's slice.
In Go, a slice has a data structure called SliceHeader which is accessible through reflect package and is what being referred to when you use unsafe.Sizeof and taking address.
The SliceHeader taking cares of three elements: Len,Cap and a Ptr. The fisrt two is trivail: they are what len() and cap() is for. The last one is a uintptr that points to the memory of the data the slice is containing.
When you shallow-copy a slice, a new SliceHeader is created but with the same content, including Ptr. So the underlying memory is not copied, but shared.

Please explain if golang types pass by value

I'm trying to make a very simple program that modifies arrays, but ran across some interesting behavior if I converted them to types. https://play.golang.org/p/KC7mqmHuLw It appears that if I have an array go passes by reference, but if I have a type then go passes by value. Is this correct?
I have two variables b and c, both are arrays of 3 integers, but c is of type cT, in every other respect they should be identical. I can assign values as b[0]=-1 and c[0]=-1, but if I pass those arrays as parameters to a function they act very differently.
The output of the program is:
before b: [1 2 3]
before c: [1 2 3]
*after b: [-1 2 0]
*after c: [-1 2 3]
*what? c: [-1 2 0]
My initial assumption is that the lines "after b" and "after c" should have been the same. Am I doing something incorrectly or am I correct about types passing to functions by value (ie. creating copy of the variable before passing to the function)?
package main
import "fmt"
type cT [3]int
func main() {
b := []int{1, 2, 3}
c := cT{1, 2, 3}
fmt.Println("before b:", b)
fmt.Println("before c:", c)
b[0] = -1
c[0] = -1
mangleB(b) // ignore return value
mangleC(c) // ignore return value
fmt.Println("*after b:", b)
fmt.Println("*after c:", c)
c = mangleC(c)
fmt.Println("*what? c:", c)
}
func mangleB(row []int) []int {
row[2] = 0
return row
}
func mangleC(row cT) cT{
row[2] = 0
return row
}
The Go Programming Language Specification
Array types
An array is a numbered sequence of elements of a single type, called
the element type.
Slice types
A slice is a descriptor for a contiguous segment of an underlying
array and provides access to a numbered sequence of elements from that
array.
Calls
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. The return parameters of the function are passed by value
back to the calling function when the function returns.
type cT [3]int
b := []int{1, 2, 3}
c := cT{1, 2, 3}
I have two variables, b and c, both are arrays of 3 integers
No, you don't!
b is a slice of int with length (len(b)) 3 and capacity (cap(b)) 3, c is an array of (len(c)) 3 int.
In Go, all parameters are passed by value. b is passed as a slice descriptor, c is passed as an array. A slice descriptor is a struct with a slice length and capacity, and a pointer to the underlying array.
See comments:
func main() {
b := []int{1, 2, 3} // slice
c := cT{1, 2, 3} // array
fmt.Println("before b:", b)
fmt.Println("before c:", c)
b[0] = -1
c[0] = -1
// passing in a slice which you can think of as ref to array
// pass by value, and it is copy of ref to array
mangleB(b) // ignore return value
// passing in copy of array (pass by value)
// yes full shallow copy of array
mangleC(c) // ignore return value
// if you ignore return modifications are lost
fmt.Println("*after b:", b)
fmt.Println("*after c:", c)
// return value is modified array
c = mangleC(c)
// c now copy of array from line 24
fmt.Println("*what? c:", c)
}
when I'm calling slice a ref I'm simplifying details here https://blog.golang.org/go-slices-usage-and-internals
https://play.golang.org/p/OAaCMhc-Ug

Golang struct gets different value from input

I am seeing weird behavior in the following code:
type A struct {
D []int8
}
func main() {
a := A{D: make([]int8, 0)}
a.D = append(a.D, 0)
b := a
c := a
b.D = append(b.D, 1)
c.D = append(c.D, 2)
fmt.Println(a.D, b.D, c.D)
}
I'm expecting output to be
[0] [0 1] [0 2]
However I got
[0] [0 2] [0 2]
Anyone know why...?
p.s. If I comment out line "a.D = append(a.D, 0)", or change the type of D from "[ ]int8" to "[ ]int", I got what I expected. Weird...
First off, changing the type doesn't fix it: https://play.golang.org/p/fHX3JAtfNz
What is happening here has to do with the mechanics of append and reference types.
Basically, all three structs are pointing at the same underlying array, but each slice has its own unique length argument.
So when you append 1 to b, it is [0 1] with a length of 2. c is still [0] with a length of 1. You then append 2 to c, making it [0 2] with a length of 2. Inadvertently, you are also changing the second value of the array in b. If you could change the length of the a without append, it would also be [0 2].
Make sense? Pointers and slices are weird. Full story is here: https://blog.golang.org/slices

How does negative index work with `Array#[]=`?

I tried to see how Array#[]= works, and played around:
enum[int] = obj → obj
enum[start, length] = obj → obj
enum[range] = obj → obj
Question 1
I have one array b holding nil at its 0 index.
b = []
b[0] # => nil
I tried to replace nil with integer 10 in the code below.
b[-1] = 10 # => IndexError: index -1 too small for array; minimum: 0
Why doesn't the code above work, but the ones below do? In case of an array with size 1, why are the indices 0 and -1 treated differently?
b[0] = 5 # => 5
b[-1] = 10 # => 10
Question 2
I created an array of size 2, and did the following:
a = [1,2]
a[-3] = 3 # => IndexError: index -3 too small for array; minimum: -2
a[-3] = [3] # => IndexError: index -3 too small for array; minimum: -2
a[-3..-4] = [3] # => RangeError: -3..-4 out of range
I believe that negative index never increases the size of an array, but I don't know why. Why did the code below succeed?
a[-2..-3] = [3,4] #=> [3, 4]
I would suggest you to take a look at the first para in Array documentation. It surprisingly says: “A negative index is assumed to be relative to the end of the array—that is, an index of -1 indicates the last element of the array, -2 is the next to last element in the array, and so on.”
That means, that you may set a[-N]th element if and only |N| <= a.size. That’s why a = [1,2] ; a[-3] = 3 fails (3 > 2).
On the other hand, there is [likely] not documented feature for ruby arrays: a[INBOUNDS_IDX..NONSENSE_IDX]=SMTH will insert SMTH before INBOUNDS_IDX index:
a=[1,2]
a[2..0]='a'
a[2..1]='b'
a[2..-100]='c'
# ⇒ [1, 2, "c", "b", "a"]
a[2..-1]='q'
# ⇒ [1, 2, "q"]
Nonsense here means “less than INBOUNDS_IDX, and not treatable as index in an negative notation” (that’s why a[2..-1] in the example above is treated as a[2..(a.size - 1)].)
Q1:
An empty array has 0 elements, so when you try to set its element 0, with negative index -1, it will give an error.
Because negative index cycles through the array from the end.
So
a = []; a[-1] = 3 makes it impossible to
a) get the element at last position, since its null
b) set its value. since it was never captured.
a[0] = 5 will work because you are telling the compiler to
a) grab the first element,
b) create one if not present, and then assign that to the value you requested.
See official api doc specifically mentioning positive index can grow size, negative index past the beginning of the array raises an error.
Q2:
The above explanation almost answers the second question as well.
Given a = [1,2]
a[-3] = 3 causes the first point of break. You are trying to access the 3rd element from the end, which does not exist. By design it breaks down.
While a[-2..-3] is within the capture range of the defined array.
You ask the interpreter to capture the second element from the last (1st from the front in this case), and try to invoke a range which is asking it to increase the array's size, and populate it with whatever you requested.
Happily, all is still well and as desired. Good to know.
Observation #1
The -1 index is related to the last element, if the array has no size, [], you can't use it until you initialize it with one or more elements.
Observation #2:
Yes, you are right, the negative index never increases size of the array, it only references a concrete existing position in the array.
Don't think the array is circular—the 0 index clued to the N-1 index—so you can't use any negative index thinking that it's valid.

Resources