I'm trying to learn the basics of Go and I'm a bit confused about the difference between call by value and call by reference in a code snippet I tested.
I tried to solve a coding game puzzle in which a solution for a tic-tac-toe field is to be calculated.
The code I'm using
Because I'm learning Go, I wanted to use a goroutine to test every field of the tic-tac-toe board, check whether this field is the solution and then put a pointer to this field in a channel for the main method to have the result. The code I used looks like this:
package main
import "fmt"
import "os"
var player int = int('O')
var opponent int = int('X')
var empty int = int('.')
type board struct {
fields [][]int
}
func main() {
lines := [3]string {"OO.", "...", "..."}
var b board
b.fillBoard(lines)
fmt.Fprintln(os.Stderr, "input board:")
b.printBoard(true)
resultChannel := make(chan *board)
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
go tryField(b, [2]int{i, j}, resultChannel) // goroutine call that isn't working as expected
}
}
fmt.Fprintln(os.Stderr, "\nresult:")
for i := 0; i < 9; i++ {
resultBoard := <- resultChannel
if (resultBoard != nil) {
resultBoard.printBoard(false)
return
}
}
// fmt.Fprintln(os.Stderr, "Debug messages...")
fmt.Println("false")// Write answer to stdout
}
func tryField(b board, field [2]int, result chan *board) {
b.printBoard(true)
fmt.Fprintln(os.Stderr, "add O to field: ", field)
fmt.Fprint(os.Stderr, "\n")
if (b.fields[field[0]][field[1]] != empty) {
result <- nil
}
b.fields[field[0]][field[1]] = player
if (b.isWon()) {
result <- &b
} else {
result <- nil
}
}
func (b *board) fillBoard(lines [3]string) {
b.fields = make([][]int, 3)
for i := 0; i < 3; i++ {
b.fields[i] = make([]int, 3)
}
for i, line := range lines {
for j, char := range line {
b.fields[i][j] = int(char)
}
}
}
func (b *board) printBoard(debug bool) {
var stream *os.File
if (debug) {
stream = os.Stderr
} else {
stream = os.Stdout
}
for i := 0; i < 3; i++ {
for j := 0; j < 3; j++ {
fmt.Fprint(stream, string(b.fields[i][j]))
}
fmt.Fprint(stream, "\n")
}
}
func (b *board) isWon() bool {
for i := 0; i < 3; i++ {
rowFull := true
colFull := true
for j := 0; j < 3; j++ {
rowFull = rowFull && b.fields[i][j] == player
colFull = rowFull && b.fields[j][i] == player
}
if (rowFull || colFull) {
return true
}
}
diagonal1Full := true
diagonal2Full := true
for i := 0; i < 3; i++ {
diagonal1Full = diagonal1Full && b.fields[i][i] == player
diagonal2Full = diagonal2Full && b.fields[i][2-i] == player
}
if (diagonal1Full ||diagonal2Full) {
return true
}
return false
}
You can run it in the go playground.
The problem
Since the last function in the snippet is declared as func tryField(b board, field [2]int, result chan *board) I assume the board b to be an indipendent copy, each time I call the method, because it's call by value. So changing this board should not affect the other boards in the other goroutines. But unfortunately changing the board in one goroutine does affect the boards in the other goroutines as the output of the programm is the following:
input board:
OO.
...
...
result:
OO.
...
...
add O to field: [1 0]
OO.
O..
...
add O to field: [2 1]
OO.
O..
.O.
As you can see the initial field has two O's at the first and the second col in the first line. Adding an O to the position [1 0] works like expected, but when adding an O to the field [2 1] the there is also an O at [1 0], which was added in the previous goroutine and shouldn't be there since it's call by value.
The question
Why does the code in my snippet behave like it's call by reference although the function doesn't use a pointer?
Thanks in advance !
Slices are references to arrays. When modifying a slice without copying it, the underlaying array will be modified. Therefore, all slices that point to the same underlaying array will see this change.
I want to take data from DB and write to excel
let's say I have a struct like:
type user struct {
ID int64
Name string
Age int
}
I can get a pointer to slice of user type form DB &[]user{}
but I want to convert that slice to a 2D slice of string [][]string{}
and here's my code try to do such job:
func toStrings(slice interface{}) [][]string {
switch reflect.TypeOf(slice).Elem().Kind() {
case reflect.Slice:
ret := [][]string{}
val := reflect.ValueOf(slice).Elem()
for i := 0; i < val.Len(); i++ {
tempSlice := []string{}
tempV := reflect.ValueOf(val.Index(i))
for j := 0; j < tempV.NumField(); j++ {
tempSlice = append(tempSlice, tempV.Field(j).String())
}
ret = append(ret, tempSlice)
}
return ret
}
return nil
}
But from the code above all I get is a slice like [<*reflect.rtype Value> <unsafe.Pointer Value> <reflect.flag Value>]
where I do it wrong?
my codes in golang playground
sorry, I found where I do it wrong, I got tempV wrong
func toStrings(slice interface{}) [][]string {
switch reflect.TypeOf(slice).Elem().Kind() {
case reflect.Slice:
ret := [][]string{}
val := reflect.ValueOf(slice).Elem()
for i := 0; i < val.Len(); i++ {
tempSlice := []string{}
// tempV should be:
tempV := val.Index(i)
// instead of reflect.ValueOf(val.Index(i))
for j := 0; j < tempV.NumField(); j++ {
tempSlice = append(tempSlice, tempV.Field(j).String())
}
ret = append(ret, tempSlice)
}
return ret
}
return nil
}
There are two problems in the code in the question. The first problem is the slice element is doubled wrapped by a a reflect.Value in the expression reflect.Value(val.Index(i)). Fix by removing the extra call to reflect.Value. The second problem is that the reflect.Value String method does not convert the underlying value to its string representation. Use fmt.Sprint (or one of its friends) to do that.
Try this:
func toStrings(slice interface{}) [][]string {
// Get reflect value for slice. Use Indirect to
// handle slice argument and pointer to slice
// argument.
v := reflect.Indirect(reflect.ValueOf(slice))
if v.Kind() != reflect.Slice {
return nil
}
var result [][]string
// For each element...
for i := 0; i < v.Len(); i++ {
// Get reflect value for slice element (a struct). Use
// Indirect to handle slice of struct and slice of
// pointer to struct.
e := reflect.Indirect(v.Index(i))
if e.Kind() != reflect.Struct {
return nil
}
// Convert fields to string and append.
var element []string
for i := 0; i < e.NumField(); i++ {
// Use fmt.Sprint to convert arbitrary Go value
// to a string.
element = append(element, fmt.Sprint(e.Field(i).Interface()))
}
result = append(result, element)
}
return result
}
Run it on the playground.
Maybe I have a simple way to resolve the problem, golang playground here
I used encoding/json to convert to json data, then convert it to map[string]interface{}.
func toStrings2(slice interface{}) [][]string {
jsonData, _ := json.Marshal(slice)
var out []map[string]interface{}
_ = json.Unmarshal(jsonData, &out)
var fields []string
if len(out) > 0 {
for k := range out[0] {
fields = append(fields, k)
}
}
var ret [][]string
for _, row := range out {
var r []string
for _, k := range fields {
r = append(r, fmt.Sprint(row[k]))
}
ret = append(ret, r)
}
return ret
}
Notice:
With the help of #CeriseLimón, I known that the code in this answer can't handle large values for User.ID.
Context: I'm trying to take any struct, and fill it with random data.
My big sticking point at the moment is that if a struct has a field that is a slice with a pointer type (ie. []*Foo), I'm unable to figure out how to create data for that struct using reflection.
Here's what my function currently looks like:
func randFill(in interface{}) interface{} {
t := reflect.TypeOf(in)
v := reflect.ValueOf(in)
if v.Kind() == reflect.Ptr {
v = v.Elem()
}
switch v.Kind() {
case reflect.Struct:
newStr := reflect.New(t).Elem()
for i := 0; i < t.NumField(); i++ {
newV := randFill(reflect.New(t.Field(i).Type).Interface())
newStr.Field(i).Set(reflect.ValueOf(newV))
}
return newStr.Interface()
case reflect.Slice:
num := rand.Intn(10)
slice := reflect.MakeSlice(v.Type(), num, num)
for j := 0; j < num; j++ {
newC := slice.Index(j)
if newC.Kind() == reflect.Ptr {
ncInt := reflect.New(newC.Type())
newC = ncInt.Elem()
}
gen := randFill(newC.Interface())
slice.Index(j).Set(reflect.ValueOf(gen))
}
return slice.Interface()
//
// ... there are other cases down here for handling primitives
//
}
return nil
}
This works great on a slice without pointer types, but here's an example of some structs that it has trouble with:
type Parent struct {
Name string
Age int
Children []*Child
}
type Child struct {
Name string
Age int
}
Where if I created a Parent{} and passed it into randFill(Parent{}), it has trouble generating values for *Child because when it gets to this line:
newC := slice.Index(j)
The value of newC at this point, when handling the slice of []*Child is (*Child)(nil), and it's a reflect.Value type.
newC := slice.Index(j)
fmt.Printf("%#v, %T", newC, newC) // Outputs: (*Child)(nil), reflect.Value
There's something I'm missing around being able to initialize a pointer type, from a reflect.Value, or I've created the incorrect type of slice, and that is the root of my problems?
When you find put that the element is a pointer, you have to create an instance of the type the pointer points to, but you're creating a new pointer. Try this:
if newC.Kind() == reflect.Ptr {
ncInt := reflect.New(newC.Type().Elem())
newC = ncInt.Elem()
}
A simple approach is to write a function that fills a reflect.Value with random data. The function calls itself recursively for structured values (slices, structs, ...).
func randFillValue(v reflect.Value) {
switch v.Kind() {
case reflect.Ptr:
v.Set(reflect.New(v.Type().Elem()))
randFillValue(v.Elem())
case reflect.Struct:
for i := 0; i < v.NumField(); i++ {
randFillValue(v.Field(i))
}
case reflect.Slice:
num := rand.Intn(10)
v.Set(reflect.MakeSlice(v.Type(), num, num))
for i := 0; i < num; i++ {
randFillValue(v.Index(i))
}
case reflect.Int:
v.SetInt(10) // TODO: fill with random int
case reflect.String:
v.SetString("random string") // TODO: fill with random string
}
// TODO: add other reflect.Kind
}
// randFill fills the value pointed to pv with random values.
func randFill(pv interface{}) {
randFillValue(reflect.ValueOf(pv).Elem())
}
Run it on the playground.
There are a couple of simplifications in this code compared to the code in the question. The first is that this answer avoids the reflect.ValueOf and .Interface() calls by working with reflect.Value. The second is that pointers are handled as a top-level case, thus eliminating the need for pointer related code in the slice element and field code.
I'm creating a utility package for my project.
Many of my string slices need a function to
1. remove duplicates
2. remove empty strings
I know 1 way to do this:1. Add a function for each case which accepts a string slice and returns a string slice
func removeEmpty(s []string) []string {
i := 0 // i points to next available pos
for _, v := range s {
if v != "" {
s[i] = v
i++
}
}
return s[:i]
}
func dedup(s []string) []string {
i := 0 // i points to next available pos
mp := map[string]bool{}
for _, v := range s {
if _, ok := mp[v]; !ok {
s[i] = v
mp[v] = true
i++
}
}
return s[:i]
}
when I apply these 2 functions to my slice, I can do:
mySlice := string[]{}
mySlice = dedup(removeEmpty(mySlice))
I want to make it somthing like:
mySlice = mySlice.dedup().removeEmpty()
or
mySlice.dedup().removeEmpty()
Maybe I can add custom method to slice[] ?
I tried writing it
func (s []string) removeEmpty() {
}
I'm getting complie error.
You can't define methods on []string, but you can define your own type based on []string and define methods on that:
type myStringSlice []string
func (s myStringSlice) removeEmpty() myStringSlice {
i := 0 // i points to next available pos
for _, v := range s {
if v != "" {
s[i] = v
i++
}
}
return s[:i]
}
func (s myStringSlice) dedup() myStringSlice {
i := 0 // i points to next available pos
mp := map[string]bool{}
for _, v := range s {
if _, ok := mp[v]; !ok {
s[i] = v
mp[v] = true
i++
}
}
return s[:i]
}
See https://play.golang.org/p/u1z_N3c_wPP.
As mentioned in the documentation:
You can only declare a method with a receiver whose type is defined in the same package as the method. You cannot declare a method with a receiver whose type is defined in another package.
So you have to declare a type on []string and then declare the method on your own type.
I am trying to find a solution to check for equality in 2 slices. Unfortanely, the answers I have found require values in the slice to be in the same order. For example, http://play.golang.org/p/yV0q1_u3xR evaluates equality to false.
I want a solution that lets []string{"a","b","c"} == []string{"b","a","c"} evaluate to true.
MORE EXAMPLES
[]string{"a","a","c"} == []string{"c","a","c"} >>> false
[]string{"z","z","x"} == []string{"x","z","z"} >>> true
Here is an alternate solution, though perhaps a bit verbose:
func sameStringSlice(x, y []string) bool {
if len(x) != len(y) {
return false
}
// create a map of string -> int
diff := make(map[string]int, len(x))
for _, _x := range x {
// 0 value for int is 0, so just increment a counter for the string
diff[_x]++
}
for _, _y := range y {
// If the string _y is not in diff bail out early
if _, ok := diff[_y]; !ok {
return false
}
diff[_y] -= 1
if diff[_y] == 0 {
delete(diff, _y)
}
}
return len(diff) == 0
}
Try it on the Go Playground
You can use cmp.Diff together with cmpopts.SortSlices:
less := func(a, b string) bool { return a < b }
equalIgnoreOrder := cmp.Diff(x, y, cmpopts.SortSlices(less)) == ""
Here is a full example that runs on the Go Playground:
package main
import (
"fmt"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
func main() {
x := []string{"a", "b", "c"}
y := []string{"a", "c", "b"}
less := func(a, b string) bool { return a < b }
equalIgnoreOrder := cmp.Diff(x, y, cmpopts.SortSlices(less)) == ""
fmt.Println(equalIgnoreOrder) // prints "true"
}
The other answers have better time complexity O(N) vs (O(N log(N)), that are in my answer, also my solution will take up more memory if elements in the slices are repeated frequently, but I wanted to add it because I think this is the most straight forward way to do it:
package main
import (
"fmt"
"sort"
"reflect"
)
func array_sorted_equal(a, b []string) bool {
if len(a) != len(b) {return false }
a_copy := make([]string, len(a))
b_copy := make([]string, len(b))
copy(a_copy, a)
copy(b_copy, b)
sort.Strings(a_copy)
sort.Strings(b_copy)
return reflect.DeepEqual(a_copy, b_copy)
}
func main() {
a := []string {"a", "a", "c"}
b := []string {"c", "a", "c"}
c := []string {"z","z","x"}
d := []string {"x","z","z"}
fmt.Println( array_sorted_equal(a, b))
fmt.Println( array_sorted_equal(c, d))
}
Result:
false
true
I would think the easiest way would be to map the elements in each array/slice to their number of occurrences, then compare the maps:
func main() {
x := []string{"a","b","c"}
y := []string{"c","b","a"}
xMap := make(map[string]int)
yMap := make(map[string]int)
for _, xElem := range x {
xMap[xElem]++
}
for _, yElem := range y {
yMap[yElem]++
}
for xMapKey, xMapVal := range xMap {
if yMap[xMapKey] != xMapVal {
return false
}
}
return true
}
You'll need to add some additional due dilligence, like short circuiting if your arrays/slices contain elements of different types or are of different length.
Generalizing the code of testify ElementsMatch, solution to compare any kind of objects (in the example []map[string]string):
https://play.golang.org/p/xUS2ngrUWUl
Like adrianlzt wrote in his answer, an implementation of assert.ElementsMatch from testify can be used to achieve that. But how about reusing actual testify module instead of copying that code when all you need is a bool result of the comparison? The implementation in testify is intended for tests code and usually takes testing.T argument.
It turns out that ElementsMatch can be quite easily used outside of testing code. All it takes is a dummy implementation of an interface with ErrorF method:
type dummyt struct{}
func (t dummyt) Errorf(string, ...interface{}) {}
func elementsMatch(listA, listB interface{}) bool {
return assert.ElementsMatch(dummyt{}, listA, listB)
}
Or test it on The Go Playground, which I've adapted from the adrianlzt's example.
Since I haven't got enough reputation to comment, I have to post yet another answer with a bit better code readability:
func AssertSameStringSlice(x, y []string) bool {
if len(x) != len(y) {
return false
}
itemAppearsTimes := make(map[string]int, len(x))
for _, i := range x {
itemAppearsTimes[i]++
}
for _, i := range y {
if _, ok := itemAppearsTimes[i]; !ok {
return false
}
itemAppearsTimes[i]--
if itemAppearsTimes[i] == 0 {
delete(itemAppearsTimes, i)
}
}
if len(itemAppearsTimes) == 0 {
return true
}
return false
}
The logic is the same as in this answer
I know its been answered but still I would like to add my answer. By following code here stretchr/testify we can have something like
func Elementsmatch(listA, listB []string) (string, bool) {
aLen := len(listA)
bLen := len(listB)
if aLen != bLen {
return fmt.Sprintf("Len of the lists don't match , len listA %v, len listB %v", aLen, bLen), false
}
visited := make([]bool, bLen)
for i := 0; i < aLen; i++ {
found := false
element := listA[i]
for j := 0; j < bLen; j++ {
if visited[j] {
continue
}
if element == listB[j] {
visited[j] = true
found = true
break
}
}
if !found {
return fmt.Sprintf("element %s appears more times in %s than in %s", element, listA, listB), false
}
}
return "", true
}
Now lets talk about performance of this solution compared to map based ones. Well it really depends on the size of the lists which you are comparing, If size of list is large (I would say greater than 20) then map approach is better else this would be sufficent.
Well on Go PlayGround it shows 0s always, but run this on local system and you can see the difference in time taken as size of list increases
So the solution I propose is, adding map based comparision from above solution
func Elementsmatch(listA, listB []string) (string, bool) {
aLen := len(listA)
bLen := len(listB)
if aLen != bLen {
return fmt.Sprintf("Len of the lists don't match , len listA %v, len listB %v", aLen, bLen), false
}
if aLen > 20 {
return elementsMatchByMap(listA, listB)
}else{
return elementsMatchByLoop(listA, listB)
}
}
func elementsMatchByLoop(listA, listB []string) (string, bool) {
aLen := len(listA)
bLen := len(listB)
visited := make([]bool, bLen)
for i := 0; i < aLen; i++ {
found := false
element := listA[i]
for j := 0; j < bLen; j++ {
if visited[j] {
continue
}
if element == listB[j] {
visited[j] = true
found = true
break
}
}
if !found {
return fmt.Sprintf("element %s appears more times in %s than in %s", element, listA, listB), false
}
}
return "", true
}
func elementsMatchByMap(x, y []string) (string, bool) {
// create a map of string -> int
diff := make(map[string]int, len(x))
for _, _x := range x {
// 0 value for int is 0, so just increment a counter for the string
diff[_x]++
}
for _, _y := range y {
// If the string _y is not in diff bail out early
if _, ok := diff[_y]; !ok {
return fmt.Sprintf(" %v is not present in list b", _y), false
}
diff[_y] -= 1
if diff[_y] == 0 {
delete(diff, _y)
}
}
if len(diff) == 0 {
return "", true
}
return "", false
}