Search code examples
gotype-conversionsliceuser-defined-types

How to convert a slice to alias slice in go?


I defined my Int type as int.

I want to convert a slice of Int to a slice of int, but got a compile error:

cannot convert c (type []Int) to type []int

How can I fix this?

package main

import (
    "fmt"
)

type Int int

func main() {
    var c = []Int{}
    var x = []int( c )
    fmt.Println(len(x))
}

Solution

  • Your Int type is not an alias of int, it's a new type with int being its underlying type. This type of conversion is not supported / allowed by the language spec. More specifically, converting a slice type to another where the element type is different is not allowed.

    The safe way

    If you only need an []int "view" of the []Int, the safe way to "convert" would be to create a copy of the []Int slice but with a type of []int, and use a for range loop and convert each individual element from Int to int type:

    var c = []Int{1, 2}
    
    x := make([]int, len(c))
    for i, v := range c {
        x[i] = int(v)
    }
    fmt.Println(x)
    

    Output (try it on the Go Playground):

    [1 2]
    

    The unsafe way

    There is also an "unsafe" way:

    var c = []Int{1, 2}
    
    var x []int = *(*[]int)(unsafe.Pointer(&c))
    fmt.Println(x)
    

    Output is the same. Try this one on the Go Playground.

    What happens here is that the address of c (which is &c) is converted to unsafe.Pointer (all pointers can be converted to this), which then is converted to *[]int (unsafe.Pointer can be converted to any pointer type), and then this pointer is dereferenced which gives a value of type []int. In this case it is safe because the memory layout of []Int and []int is identical (because Int has int as its underlying type), but in general, use of package unsafe should be avoided whenever possible.

    If Int would be a "true" alias

    Note that if Int would be a "true" alias to int, the conversion would not even be needed:

    var c = []Int{1, 2}
    
    var x []int = c
    fmt.Println(x)
    

    Output is the same as above (try it on the Go Playground). The reason why this works is because writing []Int is identical to writing []int, they are the same type, so you don't even need a conversion here.

    By using a slice type

    Also note that if you would create a new type with []int as its underlying type, you could use type conversion:

    type IntSlice = []int
    
    func main() {
        var c = IntSlice{1, 2}
    
        var x []int = []int(c)
        fmt.Println(x)
    }
    

    Output is again the same. Try this one on the Go Playground.