就地更改函数内部的切片内容和容量

I am trying to learn Go, so here is my very simple function for removing adjacent duplicates from slice for exercise from the book by Donovan & Kernighan.
Here is the code: https://play.golang.org/p/avHc1ixfck

package main
import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    removeDup(a)
    fmt.Println(a)
}

func removeDup(s []int) {
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    j := 1
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
            j++
        }
    }
    s = s[:len(tmp)]
    copy(s, tmp)
}

It should print out [0 1 3] - and I checked, actually tmp at the end of the function it has desired form. However, the result is [0 1 3 3 3 3]. I guess there is something with copy function.

Can I somehow replace input slice s with the temp or trim it to desired length?

Option 1

Return a new slice as suggested by @zerkms.
https://play.golang.org/p/uGJiD3WApS

package main
import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    a = removeDup(a)
    fmt.Println(a)
}

func removeDup(s []int) []int {
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
        }
    }
    return tmp
}

Option 2
Use pointers for pass-by-reference.
The same thing in effect as that of option1.

https://play.golang.org/p/80bE5Qkuuj

package main

import "fmt"

func main() {
    a := []int{0, 1, 1, 3, 3, 3}
    removeDup(&a)
    fmt.Println(a)
}

func removeDup(sp *[]int) {
    s := *sp
    n := len(s)
    tmp := make([]int, 0, n)
    tmp = append(tmp, s[0])
    for i := 1; i < n; i++ {
        if s[i] != s[i-1] {
            tmp = append(tmp, s[i])
        }
    }
    *sp = tmp
}

Also, refer to following SO thread: Does Go have no real way to shrink a slice? Is that an issue?

Here's two more slightly different ways to achieve what you want using sets and named types. The cool thing about named types is that you can create interfaces around them and can help with the readability of lots of code.

package main

import "fmt"

func main() {
    // returning a list
    a := []int{0, 1, 1, 3, 3, 3}
    clean := removeDup(a)
    fmt.Println(clean)
    // creating and using a named type
    nA := &newArrType{0, 1, 1, 3, 3, 3}
    nA.removeDup2()
    fmt.Println(nA)

    // or... casting your orginal array to the named type
    nB := newArrType(a)
    nB.removeDup2()
    fmt.Println(nB)
}

// using a set
// order is not kept, but a set is returned
func removeDup(s []int) (newArr []int) {
    set := make(map[int]struct{})
    for _, n := range s {
        set[n] = struct{}{}
    }
    newArr = make([]int, 0, len(set))
    for k := range set {
        newArr = append(newArr, k)
    }
    return
}

// using named a typed
type newArrType []int

func (a *newArrType) removeDup2() {
    x := *a
    for i := range x {
        f := i + 1
        if f < len(x) {
            if x[i] == x[f] {
                x = x[:f+copy(x[f:], x[f+1:])]
            }
        }
    }
    // check the last 2 indexes
    if x[len(x)-2] == x[len(x)-1] {
        x = x[:len(x)-1+copy(x[len(x)-1:], x[len(x)-1+1:])]
    }
    *a = x
}