Why can I type alias functions and use them without casting?

Turns out, this is a misunderstanding that I had about how Go dealt with types, which can be resolved by reading the relevant part of the spec:

http://golang.org/ref/spec#Type_identity

The relevant distinction that I was unaware of was that of named and unnamed types.

Named types are types with a name, such as int, int64, float, string, bool. In addition, any type you create using 'type' is a named type.

Unnamed types are those such as []string, map[string]string, [4]int. They have no name, simply a description corresponding to how they are to be structured.

If you compare two named types, the names must match in order for them to be interchangeable. If you compare a named and an unnamed type, then as long as the underlying representation matches, you're good to go!

e.g. given the following types:

type MyInt int
type MyMap map[int]int
type MySlice []int
type MyFunc func(int)

the following is invalid:

var i int = 2
var i2 MyInt = 4
i = i2 //both named (int and MyInt) and names don't match, so invalid

the following is fine:

is := make([]int)
m := make(map[int]int)
f := func(i int){}

//OK: comparing named and unnamed type, and underlying representation
//is the same:
func doSlice(input MySlice){...}
doSlice(is)

func doMap(input MyMap){...}
doMap(m)

func doFunc(input MyFunc){...}
doFunc(f)

I'm a bit gutted I didn't know that sooner, so I hope that clarifies the type lark a little for someone else! And means much less casting than I at first thought :)


Both the question and answer are pretty enlightening. However, I'd like to bring up a distinction which is not clear in lytnus's answer.

  • Named Type is different from Unnamed Type.

  • Variable of Named Type is assignable to variable of Unnamed Type, vice versa.

  • Variable of different Named Type is not assignable to each other.

http://play.golang.org/p/uaYHEnofT9

import (
    "fmt"
    "reflect"
)

type T1 []string
type T2 []string

func main() {
    foo0 := []string{}
    foo1 := T1{}
    foo2 := T2{}
    fmt.Println(reflect.TypeOf(foo0))
    fmt.Println(reflect.TypeOf(foo1))
    fmt.Println(reflect.TypeOf(foo2))

    // Output:
    // []string
    // main.T1
    // main.T2

    // foo0 can be assigned to foo1, vice versa
    foo1 = foo0
    foo0 = foo1

    // foo2 cannot be assigned to foo1
    // prog.go:28: cannot use foo2 (type T2) as type T1 in assignment
    // foo1 = foo2
}

Tags:

Types

Casting

Go