unexpected behaviour in using Go range syntax - go

Probably just because I'm new to Go, but using the range syntax over arrays of structs doesn't behave as I'd expect. I'm assuming the array item gets copied to the range index, but the copy isn't a deep copy ... so the following is a little weird. Is this behaviour documented somewhere
package main
import "fmt"
type Inner struct {
x, y int
}
type Attr struct {
a int
inside []Inner
}
var item = []Attr{
{a: 1, inside: []Inner{{2, 3}, {3, 4}}},
{a: 2, inside: []Inner{{3, 4}, {1, 2}}},
}
func main() {
fmt.Println(item)
for _,i := range item {
// A: The following has no impact on item[].a
i.a = 111
// B: But this does ... why?
i.inside[0].x = 111
}
fmt.Println(item)
for j,_ := range item {
item[j].a = 333
item[j].inside[0].x = 333
}
fmt.Println(item)
}

In the loop for _, i := range item, each i is a copy of the corresponding slice element. Suppose, you write:
i := item[0]
i.a = 111
this does not change the original element of the slice, but only its copy. However in:
i.inside[0].x = 111
inside is a slice, i.e. only a thin wrapper referring to the underlying array, which is not copied on assignment. So with i.inside you deal with the same slice as items[0].inside.
More about slices internals.

Related

Why is my (initial) variable updated when using a recursive function?

I decided to create the quick sort algorithm in go.
My code for the quick sort is:
package sorting
func QuickSort(input []int) []int {
if len(input) <= 1 {
return input
}
sorted := input
pivotIndx := len(sorted) - 1 // The index of the last item of the array
pivot := sorted[pivotIndx] // The value of the last item in the array
curLowIndx := 0
for indx, val := range sorted {
if val < pivot {
// Swap the items
sorted[indx], sorted[curLowIndx] = sorted[curLowIndx], sorted[indx]
// Increment the index on which the low position is stored.
// We need to do this so that the next item that is lower can be stored/swapped with the correct position
curLowIndx = curLowIndx + 1
}
}
sorted[curLowIndx], sorted[pivotIndx] = sorted[pivotIndx], sorted[curLowIndx]
// Sort the sub-arrays
QuickSort(sorted[:curLowIndx])
QuickSort(sorted[curLowIndx+1:])
return sorted
}
Code for the main file:
package main
import (
"fmt"
"github.com/.../.../sorting"
)
func main() {
// Sorting examples
toSort := []int{100, 20, 70, 30, 90, 40, 120, 123, 10, 23}
fmt.Println(toSort) // returns: [100 20 70 30 90 40 120 123 10 23]
shouldBeSorted := sorting.QuickSort(toSort)
fmt.Println(shouldBeSorted) // returns: [10 20 23 30 40 70 90 100 120 123]
fmt.Println(toSort) // ALSO returns: [10 20 23 30 40 70 90 100 120 123]
}
In my main function I have a slice in a variable which I want to be sorted (toSort).
I create a new variable in which I want to store the sorted slice (shouldBeSorted).
But here I find something that I did not expect, nor understand.
When I call the sorting.QuickSort(toSort) it sorts it and also assigns the return value to the shouldBeSorted variable, but next to that it also updates the toSort variable with the result from sorting.QuickSort(toSort).
I have read about the usage of pointers in go and would expect this behavior when passing a pointer through, but not when passing a 'regular' variable.
So my actual question is: why does this happen? Why does it change the toSort variable? Is there something I did wrong or is this expected and why would this be expected?
Side note:
The same thing happens in the QuickSort function it self when the recursion happens:
QuickSort(sorted[:curLowIndx])
QuickSort(sorted[curLowIndx+1:])
I first though that I would need to combine the slices I would get back, but apparently it updates the original sorted slice.
Slices in go actually consist of a struct with meta info and a pointer to a contiguous memory location that stores the actual data. Even though you're passing toSort by value, the copied meta struct still refers to the same underlying memory location. That is why toSort gets changed as well.
If you do not want this to happen, you can use copy to create a new slice and pass it on.
Slice Internals: https://blog.golang.org/slices-intro
Copy: https://golang.org/pkg/builtin/#copy
Slices are just pointers to the underlying data so when you update the given parameter, you are changing the actual data. That's why you need to copy your data:
func copySlice(s []int) []int {
c := make([]int, len(s))
copy(c, s)
return c
}
func main() {
toSort := []int{100, 20, 70, 30, 90, 40, 120, 123, 10, 23}
sorted := sorting.QuickSort(copySlice(toSort))
fmt.Println(toSort)
fmt.Println(sorted)
}

Is it possible to alter members of a struct stored in an empty interface

I have this:
type pair struct {
a, b int
}
Then I define two variables:
x := pair{ 3, 4 }
var y interface{} = x
I realize that y doesn't store a reference of x but a copy of it via the following code:
x.b = 7
fmt.Println(x)
fmt.Println(y)
// got:
// {3 7}
// {3 4}
Also see: https://github.com/golang/go/blob/master/src/runtime/iface.go#L359
Is there any way to modify pair.y member of the copied struct in y?
Tried this: (fail)
// cannot assign to y.(pair).b
y.(pair).b = 7
Tried this: (also fail)
// panic: reflect: reflect.Value.SetInt using value obtained using unexported field
v := reflect.ValueOf(y).FieldByName("b")
v.SetInt(33)
Change "b" to "B": (also fail)
type pair {
a, B int
}
// panic: reflect: reflect.Value.SetInt using unaddressable value
v := reflect.ValueOf(y).FieldByName("B")
v.SetInt(33)
Update:
I'm not going to change x.b using y. I want to change y's field b alone.
Thanks for your help, but this is not a simple question about values and references.
You need to know the pointer and address first.Use the pointer can change the value deeply.If you want y to have the same value as x, they need to point to the same address.
I found a solution:
package main
import (
"unsafe"
"fmt"
)
type pair struct {
a, b int
}
func main() {
x := pair{ 3, 4 }
var y interface{} = x
var z interface{} = y
// change x.b
x.b = 7
// change y.b
addr := (*(*[2]uintptr)(unsafe.Pointer(&y)))[1]
pp := (*pair)(unsafe.Pointer(addr))
pp.b = 8
fmt.Println(x) // {3 7}
fmt.Println(y) // {3 8}
fmt.Println(z) // {3 8}
}
It's really hack.
Can anybody provide a more natural/idiomatic one?
Summary:
assigning a concrete value to an empty interface copies the value
assigning an empty interface to another empty interface causes them to share the same underlying value

Add two items at a time to struct in for loop

I'm trying to add 2 items at once to a struct array, then continuously every 2 items create a new struct array and append to the final Container struct. I'm struggling to find the proper way of doing this.
To further illustrate what I mean:
package main
import "fmt"
type Container struct {
Collection []SubContainer
}
type SubContainer struct {
Key string
Value int
}
func main() {
commits := map[string]int{
"a": 1,
"b": 2,
"c": 3,
"d": 4,
"e": 5,
"f": 6,
}
sc := []SubContainer{}
c := Container{}
for k, v := range commits {
sc = append(sc, SubContainer{Key: k, Value: v})
}
for _, s := range sc {
c.Collection = append(c.Collection, s)
}
fmt.Println(c)
}
Link: https://play.golang.org/p/OhSntFT7Hp
My desired behaviour is to loop through all the commits, and every time the SubContainer reaches len(2), append to the Container, and create a new SubContainer until the for loop is complete. If there's an uneven number of elements, then the last SubContainer would just hold one element and append to Container like normal.
Does anyone have any suggestions on how to do this? Apologies if this is a obvious answer, very new to Go!
You can "reset" a slice by setting it to nil. Also, you may not be aware that nil-slices work just fine with append:
var sc []SubContainer
c := Container{}
for k, v := range commits {
sc = append(sc, SubContainer{Key: k, Value: v})
if len(sc) == 2 {
c.Collection = append(c.Collection, sc...)
sc = nil
}
}
if len(sc) > 0 {
c.Collection = append(c.Collection, sc...)
}
https://play.golang.org/p/ecj52fkwpO

Create Struct instance with initialization from slices of data golang

I have a data with array of array.
data := [][]int{{1,2,3}, {4,5,6}}
and struct
type A struct {
I, J, K int
}
Now I want to create instance run time for struct A with each array from data, How do I achieve that? If reflect is a way, then tell how?
This is just an example that I want to show you. But let's say if struct A contains 26 fields from A to Z with type of int and I have 100 slices of data from which I can create/init my struct A, then how it could be possible without using dot notation on struct and just looping over field index and assign that field from slice data?
package main
import (
"fmt"
)
type A struct {
I, J, K int
}
func main() {
data := [][]int{
{1, 2, 3},
{4, 3, 2},
}
var a A
// create instance of type A with params
// initialization for each array in data
fmt.Println(a)
}
Please help me at this link: https://play.golang.org/p/rYuoajn5Ln
I'm not sure if that is what you are looking for, but you can create those objects in a simple loop:
func main() {
data := [][]int{
{1, 2, 3},
{4, 3, 2},
}
for _, intArr := range data {
a := NewA(intArr)
// a:= A{I: ints[0], J: ints[1], K: ints[2]}
fmt.Println(a)
}
}
Full solution available at https://play.golang.org/p/j7fxbmu3jp
Here it is, for a more compact version...
Just range over your "data" array of arrays and create a new "A" from each index.
No need to do that in a separate function.
for _, arr := range data {
a := A{I: arr[0], J: arr[1], K: arr[2]}
fmt.Println(a)
}
Full solution here: https://play.golang.org/p/jyN7f9c-o-

Overlapping in treap package from stathat?

According to this link stathat uses overlapping with their treap:
GoLLRB is great and there's no reason you should switch. We thought
the idea behind treaps was an elegant solution to our problem, so we
implemented it. We liked the interface that GoLLRB provided, so we
mimicked it in our implementation.
One thing we added to the treap package is to allow you to iterate
using an overlap function, so you can get all the keys in [3,9), for
example. We use this a lot, often with a struct as the key.
Patrick
I am playing with the following code and have no idea how to continue:
package main
import(
"reflect"
"fmt"
"github.com/stathat/treap"
)
func IntLess(p, q interface{}) bool {
return p.(int) < q.(int)
}
func BucketOverlap(a, b interface{}) bool {
return false
}
func main() {
tree := treap.NewOverlapTree(IntLess, BucketOverlap)
tree.Insert(5, "a")
tree.Insert(7, "b")
tree.Insert(2, "c")
tree.Insert(1, "d")
for v := range tree.IterateOverlap([]int{2,5}) {
fmt.Printf("val: %v\n", v)
}
}
let's say I want to get keys in range [2,5] => [c,a]
The first place I'd start would be the tests for the stathat treap code:
https://github.com/stathat/treap/blob/master/treap_test.go#L164
It seems that what you're doing is trying to pass a slice of keys when it is expecting a single one. You are also trying to do vector operations (i.e. range overlap) on a value that is scalar (i.e. int).
Maybe I am misunderstanding the point of the overlap, but my understanding is that the use for it is as an interval tree:
key1 := []int{1, 3}
key2 := []int{2, 4}
key3 := []int{5, 6}
These are intervals (low and high). key1 overlaps key2, and vice-versa. Neither overlap key3. In this case, the overlap would be useful (i.e. IterateOverlap([]int{2,3}) would give me key1 and key2, whereas IterateOverlap([]int{3,5}) would return all).
I'm not sure how you'd iterate over these entries. Maybe this:
for i := 2; i <= 5; i++ {
fmt.Printf("val: %v\n", tree.Get(i))
}
Again, I've not used this implementation, so forgive me if I'm barking up the wrong tree.
I have found a solution using GoLLRB:
package main
import (
"fmt"
"github.com/petar/GoLLRB/llrb"
)
type Item struct {
key int
value string
}
func lessInt(a, b interface{}) bool {
aa := a.(*Item)
bb := b.(*Item)
return aa.key < bb.key
}
func main() {
tree := llrb.New(lessInt)
tree.ReplaceOrInsert(&Item{5, "a"})
tree.ReplaceOrInsert(&Item{7, "b"})
tree.ReplaceOrInsert(&Item{2, "c"})
tree.ReplaceOrInsert(&Item{1, "d"})
//tree.DeleteMin()
c := tree.IterRangeInclusive(&Item{key: 2}, &Item{key: 5})
for item := <-c; item != nil; item = <-c {
i := item.(*Item)
fmt.Printf("%s\n", i.value)
}
}
Still I am wondering if this is also possible using stathat's treap.

Resources