According to the builtin api docs, append() will reallocate and copy to a new array block when the capacity of the original slice is not large enough.
Here is a (simplified version of) a recursive algorithm for creating combinations of an alphabet (in this case booleans). Members of the alphabet (true, false) are recursively added to a slice until it is the correct length, at which point it is sent over the channel.
package main
import (
"fmt"
)
func AddOption(c chan []bool, combo []bool, length int) {
if length == 0 {
fmt.Println(combo, "!")
c <- combo
return
}
var newCombo []bool
for _, ch := range []bool{true, false} {
newCombo = append(combo, ch)
AddOption(c, newCombo, length-1)
}
}
func main() {
c := make(chan []bool)
go func(c chan []bool) {
defer close(c)
AddOption(c, []bool{}, 4)
}(c)
for combination := range c {
fmt.Println(combination)
}
}
Here is the playground link to this code. In the output:
[true true true true] !
[true true true false] !
[true true true false]
[true true true false]
[true true false true] !
[true true false false] !
[true true false false]
[true true false false]
[true false true true] !
[true false true false] !
[true false true false]
[true false true false]
[true false false true] !
[true false false false] !
[true false false false]
[true false false false]
[false true true true] !
[false true true false] !
[false true true false]
[false true true false]
[false true false true] !
[false true false false] !
[false true false false]
[false true false false]
[false false true true] !
[false false true false] !
[false false true false]
[false false true false]
[false false false true] !
[false false false false] !
[false false false false]
[false false false false]
Lines ending in an exclamation mark are those sent into the channel from AddOption. Those without are what emerges on the other side (i.e. in main()). It is clear that the slices send over the channel are changed after they are sent.
Since AddOption returns immediately after sending the slice, the modification has to come from the code block
var newCombo []bool
for _, ch := range []bool{true, false} {
newCombo = append(combo, ch)
AddOption(c, newCombo, length-1)
}
But, according to the docs, append() should return a new slice (cap(combo) is not large enough). According to this answer, the slice descriptor sent to AddOption should be a copy; is that not true? As far as I can tell, either the value sent as the second argument to AddOption() is either a pointer to a slice descriptor, or append() is not returning a new slice.