0

I encountered a strange error in Golang today, tangential to this question. Given the following,

package main

import (
    "fmt"
)

func main() {
    fmt.Println("Hello, playground")
    data := []string{"A", "B", "C"}
    testFunc(data...)
}

func testFunc(items ...interface{}) {
    for i, item := range items {
        fmt.Printf("Item %d: %v\n", i, item)
    }
}

I get an error because []string cannot be casted to []interface{}. This makes no sense because I could do testFunc("A", "B", "C") and it would work as expected. This tells me that the ellipsis is just a mask for a slice of the given type and so, when I call testFunc, the compiler is comparing the slice-type with the slice-type expected by the variadic argument, and if they're not equal, returning an error. However, when sending a list of strings to the variadic argument, each string is type-checked against interface{} instead. So, then, my question is: why does Golang do a type-check of the slice-types rather than doing an element-wise type-check?

Woody1193
  • 7,252
  • 5
  • 40
  • 90
  • If you have `[]string` and the function expects `...interface{}`, you can't pass it. You have to first create a `[]interface{}` from the individual `string` elements, then you may pass that like `data...`. – icza Sep 17 '20 at 08:01
  • What kind of answer are you expecting here? That's how the language works. The question you linked points you in the right direction, `[]string` can't be casted to `[]interface` so it's not allowed. In general golang will never do expensive operations implicitly, so this makes a lot of sense to me. – super Sep 17 '20 at 08:04
  • @super Except I don't understand how it's more expensive than calling the function with explicit arguments. Are you saying that aliasing a slice of strings as a slice of `interface{}` is inherently more expensive than doing the same thing with a variadic list? That doesn't really make sense to me. – Woody1193 Sep 18 '20 at 09:05
  • @Woody1193 Yes, that's exactly what I mean and what the andwer you linked to tells you. A `[]string` and a `[]interface` has different underlying memory mappings, so you need to actually convert one element at a time. If that was done implicitly it would hide a possibly very expensive operation. When you pass in string literals directly the compiler doesn't need to convert anything. It can just create the `interface{}` object directly, or in this case it can probably inline the whole function. – super Sep 19 '20 at 16:01

0 Answers0