How to convert a slice to alias slice in go?
Asked Answered
C

4

6

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))
}
Cati answered 17/5, 2018 at 8:0 Comment(1)
What you do is not aliasing. You do not need aliasing. Forget that term. Take the Tour of Go which explains how to convert types with identical underlying types.Bratton
M
12

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.

Markus answered 17/5, 2018 at 8:20 Comment(5)
Downvoter care to comment?Markus
This answer seems fine to me. Yes, downvoter should put down his views, am upvoting it to make up :) p.s.: I note that you later added a part to your answer which incidentally I also illustratedNortherly
There is nothing unsafe about the "unsafe" solution.Bootlace
@Bootlace There's nothing "unsafe" with the current version. The Go backward compatibility guarantee does not guarantee apps using package unsafe will continue to work with future versions and on all platforms. It's unlikely that this unsafe solution will break in a future version, but there's no guarantee. There is guarantee that the safe way will continue to work on all platforms in future releases too.Markus
If past design decisions are any indication, I would not put it past them.Bootlace
S
0

The problem is that you are not creating Int as an alias, doing

type Int int

Will create Int as a new type that can't interoperate with int.

The proper way to create Int as an alias is

type Int = int

With this change your program is ok.

Solita answered 17/5, 2018 at 8:15 Comment(1)
I don’t know why the downvote, the @johlo's answer really show how to create an alias in Go (Go 1.9 and higher). Nobody else mention the existence of real alias in Go. See here: golang.org/doc/go1.9#languageBroeder
E
0

Technically, type Int int does not define an alias, but a completely new type. Even though Int and int now have identical underlying types and can be converted to each other, that does not apply to slices. More about allowed conversions is in the spec.

Easily answered 17/5, 2018 at 8:20 Comment(0)
N
0

Actually, a slice a simply points to an underlying array of the designated type (in this case the types are different, Int and int). So unless your underlying type is the same a conversion won't work. Just to illustrate this something like this would work though:

package main

import (
    "fmt"
)

type Int int
type IntSl []int

func main() {
    var c = IntSl{2, 3, 4}
    var x []int
    x = []int(c)
    var a Int
    var b int
    a = 1
    b = int(a)
    fmt.Println(len(x), a, b, c)
}

Playground : https://play.golang.org/p/ROOX1XoXg1j

As @icza points out there's the unsafe way & of course you can always do the conversion looping over each of the elements which could be expensive.

Northerly answered 17/5, 2018 at 8:37 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.