For a project I’m working on, I have to manipulate a lot of slices. One of those manipulations is a simple function that creates a new slice filled with the same repeated value.

Being still influenced by other languages I worked with previously, I decided to create a function that I could use on any type.

I made my homework and looked at how it works in the standard library. I found strings.Repeat and bytes.Repeat. Ok, two nearly identical implementations for doing the same thing.

Knowing how smart the Go developers are, I was sure there was a reason for that but decided to pursue.

So I started with a simple solution:

func Repeat(any interface{}, count int) []interface{} {
    s := make([]interface{}, count)
    for j := 0; j < count; j++ {
        s[j] = any
    }
    return s
}

func main() {
    slice := Repeat(42, 4)
    fmt.Println(slice)
}

This worked fine. So I decided to continue some testing.

for _, i := range slice {
    fmt.Printf("%v ",i)
}

After that, I decided that it was fine. I wrote tests, added comments to the functions, added parameters tests. and then I started to use it in the rest of the code. What a fool I was!

The real code use Repeat to create a slice of ‘blank’ struct and insert it at the beginning of another slice. For simplicity purpose, I’ll just use an int slice in this example. Here is what il looks like:

var other []int
slice := Repeat(42, 4)
other = slice
And the compiler gave me this: cannot use slice (type []interface {}) as type []int in assignment

I didn’t give up so I tried type assertion:

other = slice.([]int)
Now It returned this : invalid type assertion: slice.([]int) (non-interface type []interface {} on left) Of course it’s not an interface, it’s a slice of interfaces! I was trying to put a slice of interface into a slice of ints. Conversion wouldn’t have helped either.

There is of course a solution:

other = make([]int, 4)
for i, j := range slice {
    other[i] = j.(int)
}

You have to copy all the elements one by one. It looks pretty similar to the code within Repeat. and thus looks a little redundant.

Go is a strictly typed language designed to avoid doing bad things with your code. The correct solution is to create a different implementation for each type it uses. Just like they did in the standard library.

func Repeat(i int, count int) []int {
    s := make([]int, count)
    for j := 0; j < count; j++ {
        s[j] = i
    }
    return s
}

func main() {
    var other []int
    slice := Repeat(42, 4)
    other = slice
    fmt.Println(other)
}

There is no redundant code and no hazardous type conversion.

Go keeps you doing good things.