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.
Related
I am a beginner and hope to get your help
it is remove-duplicates-from-sorted-array
func remove(nums []int)int{
i,j:= 0,0
//Why is it wrong to use if here?
// if j< len(nums)
for j < len(nums){
if i==0 || nums[i-1]!= nums[j]{
nums[i] = nums[j]
i++
j++
}else{
j++
}
}
return i
}
func main(){
nums := []int{1,2,2,3,5,5}
result := remove(nums)
fmt.Println(result)
}
please help me
On short notice, here's what I have:
func remove(nums []int) int {
temp := map[int]string{}
for _, n := range nums {
temp[n] = "exist"
}
result := []int{}
for n, _ := range temp {
result = append(result, n)
}
return result
}
And the output is:
[1 2 3 5]
Iterate through the slice and put into a map.
Iterate through the map and put into a slice.
Return the new slice.
It is a sorted list of numbers, so you can store the last number added into the results list and skip adding into the result list if the next number is the same.
func remove(nums []int) []int {
if len(nums) == 0 {
return []int{}
}
result := []int{nums[0]}
current := nums[0]
for _, num := range nums {
if current == num {
continue
}
result = append(num)
current = num
}
return result
}
If you are asking about why is it wrong to use for j < len(nums), its not wrong, but using for _, num := range nums would make your life easier as you don't have to keep track of where you are in the array.
In C you can use the function write() from the unistd.h library.
write() is faster than printf(), and allows you to write to the standard output (or a file) before a Segfault breaks your code.
When debugging, I wish to write to the standard output before my Go code panics. In general, how do I do that?
I have the following code (to find the shortest word in a string of words) which is panicking and I want to isolate where, by inserting write methods.
func FindShort(s string) int {
i := 0
j := 0
min := math.MaxInt32
for true {
for s[i] == ' ' {
i++
j++
}
for s[j] != ' ' && j < len(s) {
j++
}
if j > i && (j - i) < min {
min = j - i
}
i = j
if j == len(s) {
break
}
}
return min
}
you could use a defered function that calls the recover function, the function below will result in "Recovered panic here"
defer func() {
r := recover()
if r != nil {
fmt.Println("Recovered", r)
}
}()
panic("panic here")
Your code checks all lines if it contains a space, but it isn't checking if the line ends (end of line / end of file / line feed). There is a easier way to check what the shortest word is :
package main
import (
"fmt"
"math"
"strings"
)
func main() {
min := math.MaxInt32
shortest := math.MaxInt32
s := strings.Split("this is a test", " ")
for key, value := range s {
if len(value) < min {
min = len(value)
shortest = key
}
}
fmt.Print(s[shortest])
}
var Reverse = func(slice interface{}) {
s := reflect.ValueOf(slice)
// if s is a pointer of slice
if s.Kind() == reflect.Ptr {
s = s.Elem()
}
i := 0
j := s.Len() - 1
for i < j {
x, y := s.Index(i).Interface(),
s.Index(j).Interface()
s.Index(i).Set(reflect.ValueOf(y))
s.Index(j).Set(reflect.ValueOf(x))
i++
j--
}
}
I found this way works.But it is not elegant....
I know there is a method "Swapper" in reflect package. But I don't know how to make it work if the argument of above function is a pointer of slice.
Really appreciate.
Your code works fine. To use reflect.Swapper, just pass s.Interface() into it:
var Reverse = func(slice interface{}) {
s := reflect.ValueOf(slice)
// if s is a pointer of slice
if s.Kind() == reflect.Ptr {
s = s.Elem()
}
swp := reflect.Swapper(s.Interface())
for i,j :=0,s.Len() - 1; i<j; i,j = i+1,j-1 {
swp(i,j)
}
}
Playground: https://play.golang.org/p/DSq_iZRZX4b
How to realize a nested iterator that takes a depth argument. A simple iterator would be when depth = 1. it is a simple iterator which runs like a simple for loop.
func Iter () chan int {
ch := make(chan int);
go func () {
for i := 1; i < 60; i++ {
ch <- i
}
close(ch)
} ();
return ch
}
Output is 1,2,3...59
For depth = 2 Output would be "1,1" "1,2" ... "1,59" "2,1" ... "59,59"
For depth = 3 Output would be "1,1,1" ... "59,59,59"
I want to avoid a nested for loop. What is the solution here ?
I don't know if it is possible to avoid nested loops, but one solution is to use a pipeline of channels. For example:
const ITER_N = 60
// ----------------
func _goFunc1(out chan string) {
for i := 1; i < ITER_N; i++ {
out <- fmt.Sprintf("%d", i)
}
close(out)
}
func _goFuncN(in chan string, out chan string) {
for j := range in {
for i := 1; i < ITER_N; i++ {
out <- fmt.Sprintf("%s,%d", j, i)
}
}
close(out)
}
// ----------------
// create the pipeline
func IterDepth(d int) chan string {
c1 := make(chan string)
go _goFunc1(c1)
var c2 chan string
for ; d > 1; d-- {
c2 = make(chan string)
go _goFuncN(c1, c2)
c1 = c2
}
return c1
}
You can test it with:
func main() {
c := IterDepth(2)
for i := range c {
fmt.Println(i)
}
}
I usually implement iterators using closures. Multiple dimensions don't make the problem much harder. Here's one example of how to do this:
package main
import "fmt"
func iter(min, max, depth int) func() ([]int, bool) {
s := make([]int, depth)
for i := range s {
s[i] = min
}
s[0] = min - 1
return func() ([]int, bool) {
s[0]++
for i := 0; i < depth-1; i++ {
if s[i] >= max {
s[i] = min
s[i+1]++
}
}
if s[depth-1] >= max {
return nil, false
}
return s, true
}
}
func main() {
// Three dimensions, ranging between [1,4)
i := iter(1, 4, 3)
for s, ok := i(); ok; s, ok = i() {
fmt.Println(s)
}
}
Try it out on the Playground.
It'd be a simple change for example to give arguments as a single int slice instead, so that you could have per-dimension limits, if such a thing were necessary.
I have the following code, feel free to offer pointers if you wish:
package main
import (
"fmt"
)
type Grid struct {
rows int
cols int
tiles []Tile
}
type Tile struct {
x int
y int
contents int
}
func (g Grid) AddTile(t Tile) {
g.tiles = append(g.tiles, t)
}
func (g *Grid) Row(num int) []Tile {
numTiles := len(g.tiles)
row := []Tile{}
for i := 0; i < numTiles; i++ {
tile := g.tiles[i]
if (tile.y == num) {
row = append(row, tile)
}
}
return row
}
/*
HERE IS WHERE I NEED HELP
*/
func (g *Grid) SetRow(num, val int) {
row := g.Row(num)
rowLength := len(row)
for i := 0; i < rowLength; i++ {
tile := &row[i]
tile.contents = val
}
}
func (g Grid) Col(num int) []Tile {
numTiles := len(g.tiles)
col := []Tile{}
for i := 0; i < numTiles; i++ {
tile := g.tiles[i]
if (tile.x == num) {
col = append(col, tile)
}
}
return col
}
func MakeTile(x, y int) Tile {
tile := Tile{x: x, y: y}
return tile
}
func MakeGrid(rows, cols int) Grid {
g := Grid{ rows: rows, cols: cols}
for r := 1; r <= rows; r++ {
for c := 1; c <= cols; c++ {
g.tiles = append(g.tiles, MakeTile(r, c))
}
}
return g
}
func main() {
g := MakeGrid(256, 256)
g.SetRow(100, 5)
fmt.Println(g.Row(100))
}
I am doing this, more than anything, as a simple project to help me learn Go. The problem that is have run in to is here
/*
HERE IS WHERE I NEED HELP
*/
func (g *Grid) SetRow(num, val int) {
row := g.Row(num)
rowLength := len(row)
for i := 0; i < rowLength; i++ {
tile := &row[i]
tile.contents = val
}
}
Somewhere it seems like I need to be making a pointer to the actual Tiles that I'm trying to modify. As it is the SetRow function doesn't actually modify anything. What am I doing wrong? Keep in mind I just started learning Go 2 days ago, so this is a learning experience :)
One way to accomplish your goal is to use pointers to tiles throughout the code. Change the Grid tiles field to:
tiles []*Tile
and several related changes through the code.
Also, change all the methods to use pointer receivers. The AddTile method as written in the question discards the modification to the grid on return.
playground example