6

Prototype function

func test(i ...interface{}) {
    // Code here
}

Intended use

type foo struct {
    // Fields
}

foos := []foo{
    // foo1, foo2 ...
}

test(foos...) // ERROR
test(foos[1], foos[2], ...) // OK

Error

cannot use foos (variable of type []foos) as []interface{} value in argument to test

Description

The intended use is to be used like the built-in function append().

https://golang.google.cn/pkg/builtin/#append

func append(slice []Type, elems ...Type) []Type

Although, as I've seen append() doesn't use interface{}, which is strange, since anywhere that I searched all people say to use interface{} when you don't know the type. But they don't. Nope, append() uses a "build-in" type called Type, which apparently the docs say that it's a int. Although, I cannot use it. There isn't such type. And neither I would know how to use it if there was.

https://golang.google.cn/pkg/builtin/#Type

type Type int

So, I'm very confused here.

Questions

  1. Why does the spread operator not work as intended? For example, in Javascript the spread operator just spreads the array into items. But in Golang it seems like it keeps the same array parameter type as it is but gives the compiler later an instruction to spread it. Which is odd.

  2. Are we even able to make similar custom mechanisms like append() at all? Or am I a dummy and I'm using something wrong anyway?

Eksapsy
  • 1,541
  • 3
  • 18
  • 26
  • 3
    `append` has built-in function super powers. – peterSO Sep 02 '19 at 00:48
  • 3
    The builtin package documentation uses `Type` as a placeholder for any type. This use of `Type` is not valid Go syntax and is not useable in application defined functions. As peterSO says, append has super powers. – Charlie Tumahai Sep 02 '19 at 00:59
  • I see. I feel like that is a bit unfair to be honest. Thanks for clearing this out. So my question is still valid. Why and who gave the downvote? It's a legit question that will surely help other people too and I made it as crystal clear as possible. I dont know what stackoverflow wants anymore. – Eksapsy Sep 02 '19 at 01:24
  • 1
    A future version of Go may give you the power of `append` and other builtins. See https://blog.golang.org/why-generics. – Charlie Tumahai Sep 02 '19 at 01:30
  • @CeriseLimón If you would feel like it, you could form an answer since I think you provide all the information there is to answer the question. I'll mark it as solved when possible. – Eksapsy Sep 02 '19 at 01:47

3 Answers3

7

I think that this is the issue that you are running into here.

https://github.com/golang/go/wiki/InterfaceSlice

I am not an expert in this but have hit this before, the "slice of empty interface" is not an interface and therefore cannot be replaced by any type which is the issue that you are having, it has to do with the memory structure being different. The above has a far better explanation than one that I can give.

John Dowling
  • 582
  • 6
  • 23
  • I see. Looking it up again, I can see that `...interface{}` is interpreted as `[]interface{}`. I just thought this shouldn't be the case. Because the intention with the spreading operator is not to say "I want an array of interfaces", but to say "I want a set of interface{} elements". That's why I thought this was strange & confusing, especially when coming from a JS Background :3. Thanks by the way. – Eksapsy Sep 02 '19 at 12:12
3

You can typecast your typed slice to get what you need:

generic := make([]interface{}, 0)
for _, f := range foos {
  generic = append(generic, f)
}
test(generic...)  // works
Luke Sneeringer
  • 9,270
  • 2
  • 35
  • 32
  • You could `generic := make([]interface{}, len(foos))`, `for i, f := range foos`, and `generic[i] = f`, since the length of `foos` is known. Looks like this is linked to in the other answer: https://github.com/golang/go/wiki/InterfaceSlice#what-can-i-do-instead – Chris Redford Mar 07 '21 at 14:42
1

Combining the two non-negative answers into what I feel is the best solution:

interfaceSlice := make([]interface{}, len(foos))
for i, v := range foos {
    interfaceSlice[i] = v
}
test(interfaceSlice...)

Partially inspired by:

https://github.com/golang/go/wiki/InterfaceSlice#what-can-i-do-instead

Chris Redford
  • 16,982
  • 21
  • 89
  • 109