-2

I'm slightly confused about the behavior of the unpack/spread operator when trying to append into a slice of empty interfaces (i.e. []interface{}) from an slice of a custom type. I expected it to work since the interface{} can hold any type, but I'm currently receiving errors when trying to do this operation.

The following snippet illustrates the issue:

package main

import (
    "fmt"
)

type CustomType struct {
    value int
}

func main() {
    data := []interface{}{}

    values := []CustomType{
        {value: 0},
        {value: 1},
    }

    //  This does not compile:
    // data = append(data, values...)

    // But this works fine
    data = append(data, values[0])

    for _, value := range data {
        fmt.Printf("Value: %v\n", value)
    }
}

Go playground with the snippet above

I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type. When I append the values one by one, then compiler is OK with the operation.

Why is unpacking the values slice not allowed in this situation?

Eduardo macedo
  • 762
  • 1
  • 4
  • 16
  • 5
    In the code `append(data, values...)`, `values` is passed as is to `append`. The elements of `values` are not spread or unpacked to individual arguments. The code fails to compile because a `[]CustomType` is not assignable to `[]interface{}`. – Charlie Tumahai Oct 21 '22 at 00:08
  • 3
    In Go, interface types are only "special" in a *few*, very *limited* senses. In general, they act the same as other types in this **strongly typed** language. More specifically, the relevant special case is that a value of type `CustomType` is [assignable](https://go.dev/ref/spec#Assignability) to a variable of type `interface{}`. This says *nothing* about composite types such as `[]CustomType` and `[]interface{}`. – Hymns For Disco Oct 21 '22 at 00:14

1 Answers1

2

Obviously, the code data = append(data, values...) could be compiled error cannot use values (variable of type []CustomType) as type []interface{} in argument to append

Per faq Can I convert a []T to an []interface{}?

Not directly. It is disallowed by the language specification because the two types do not have the same representation in memory. It is necessary to copy the elements individually to the destination slice. This example converts a slice of int to a slice of interface{}:

 t := []int{1, 2, 3, 4}
 s := make([]interface{}, len(t))
 for i, v := range t {
     s[i] = v
 }

For your question

I expected to be able to unpack the values slice and append its elements into the data slice since it can hold any values, but the compiler does not like that and complains about the values array not being of []interface{} type.

The difference between the element type CustomType and interface

  • type CustomType represented in memory like value
  • type interface{} represented in memory
    • pointer to type CustomType
    • value

They have different representations in memory.

Besides that, converting a []CustomType to an []interface{} is O(n) time because each value of the slice must be converted to an interface{}. It could be one complex operation.

zangw
  • 43,869
  • 19
  • 177
  • 214