Slice changed itself after next loop

Hi all:
I’m a newbie to Golang and I’m learning Golang from Miek Gieben’s “Learning Go” , when I try his answer code of “Number cruncher”,it gave the wrong answer.
here is my simplified code just for debug.

    package main

    import (
    	"fmt"
    	"strconv"
    )

    const (
    	_ = 1000 * iota
    	ADD
    	SUB
    	MUL
    	DIV
    	MAXPOS = 11
    )

    var mop = map[int]string{ADD: "+", SUB: "-", MUL: "*", DIV: "/"}

    func rpnstr(r []int) (ret string) {
    	s := make([]string, 0)
    	for k, t := range r {
    		switch t {
    		case ADD, SUB, MUL, DIV:
    			fmt.Printf("k=%d s0=%v len(s)=%d \n", k, s, len(s))
    			a, s := s[len(s)-1], s[:len(s)-1]
    			b, s := s[len(s)-1], s[:len(s)-1]
    			if k == len(r)-1 {
    				s = append(s, b+mop[t]+a)
    			} else {
    				s = append(s, "("+b+mop[t]+a+")")
    			}
    			fmt.Printf("k=%d s1=%v len(s)=%d \n", k, s, len(s))
    		default:
    			{
    				s = append(s, strconv.Itoa(t))
    			}
    		}
    	}
    	for _, v := range s {
    		ret += v
    	}
    	return
    }

    func main() {
    	list := []int{75, 8, 6, MUL, ADD, 8, MUL, 7, SUB, 1, DIV}
    	print(rpnstr(list))
    }

it’s a part of Reverse Polish notation,we could see the output log by run it. just like:

k=3 s0=[75 8 6] len(s)=3 
k=3 s1=[75 (8*6)] len(s)=2 
k=4 s0=[75 (8*6) 6] len(s)=3 
k=4 s1=[75 ((8*6)+6)] len(s)=2 
k=6 s0=[75 ((8*6)+6) 6 8] len(s)=4 
......
$ go version
go version go1.8.1 windows/amd64

when k=3 (t = MUL), it pop 6 and 8 and combinated as "(86) which is just we want,but in the next loop ,when k=4 (t = ADD), the value of slice s changed from [75 (86)] to [75 (8*6) 6] itself without any operation,where’s the last 6 come from? I think Miek’s answer is right but I couldn’t tell what’s wrong with it.
Anybody knows? Any idea will be appreciated! thanks.

Here,

you are declaring a new slice s that shadows the s from the outer scope, meaning it does not get “popped” for the next iteration of the loop. The result is confusing since part of the array backing the slice was overwritten anyway by the append. Instead,

var a, b string
a, s = s[len(s)-1], s[:len(s)-1]
b, s = s[len(s)-1], s[:len(s)-1]

(https://play.golang.org/p/htNGEyYt3y)

will do what you expect. Or, possibly a bit more clear,

a := s[len(s)-1]
b := s[len(s)-2]
s = s[:len(s)-2]

(https://play.golang.org/p/WphiSj6Exz)

If this does not make sense to you, https://blog.golang.org/go-slices-usage-and-internals is a good read.

1 Like

Thank you Jakob! you save my life :joy: It really make sense.

1 Like

You should file a bug report on the book as well. :wink:

All right :grin:

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.