Passing elements of a slice to `fmt.Println` using the `…` operator to spread arguments doesn't work. Why?

Issue

I have an array/slice of elements (bytes in my example), and I want to print these values using ftm.Println. I can of course just loop over the elements in the array and print them that way, but I thought it would be nicer/shorter if I just passed the elements using ... operator instead.

So I tried this:

    b := []byte{1,2,3,4}
    fmt.Println(b...)

This results in an error:

cannot use b (variable of type []byte) as type []any in argument to fmt.Println"

Can someone explain why that doesn’t work?

I was assuming that fmt.Println is a variadic function that is capable of handling any number of elements of any type (the []any in the error message seems to suggest that is the case). So it is a bit surprising to me that Println seems not capable of handling it when I pass it 4 bytes.

Indeed when we pass these same bytes like this it works just fine:

    fmt.Println(b[0], b[1], b[2], b[3])

So why doesn’t it work when we these bytes using b... instead? Isn’t that essentially the same thing (i.e. in both cases what we are doing is passing 4 bytes as separate arguments to fmt.Println?

Solution

Variadic arguments are passed as a slice. In the following:

fmt.Println(b[0], b[1], b[2], b[3])

The compiler creates a slice []any from the four elements, and passes that slice.

However,

b := []byte{1,2,3,4}
fmt.Println(b...)

tries to pass a []byte, which is not compatible with the function signature.

This works though:

b := []any{1,2,3,4}
fmt.Println(b...)

[]byte cannot be substituted for []any because a byte array is structurally different from an interface array. Thus, an element-by-element conversion is necessary, which can be expensive. In general, Go language does not perform implicit conversions that can be expensive. If you need to do it, then you have to make it explicitly yourself.

Answered By – Burak Serdar

Answer Checked By – Clifford M. (GoLangFix Volunteer)

Leave a Reply

Your email address will not be published.