Types
Types in Go are divided into 2 categories: named and unnamed. Besides predeclared types (such as int, rune, etc), you can also define named type yourself. E.g.:
type mySlice []int
Unnamed types are defined by type literal. I.e., []int is an unnamed type.
According to Go spec, there is an underlying type of every type:
Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the type to which T refers in its type declaration.
So, in above example, both named type mySlice and unnamed type []int have the same underlying type: []int.
Go has strict rules of assigning values of variables. For example:
package main
import "fmt"
type mySlice1 []int
type mySlice2 []int
func main() {
var s1 mySlice1
var s2 mySlice2 = s1
fmt.Println(s1, s2)
}
The compilation will complain the following error:
cannot use s1 (type mySlice1) as type mySlice2 in assignment
Although the underlying type of s1 and s2 are same: []int, but they belong to 2 different named types (mySlice1 and mySlice2), so they can't assign values each other. But if you modify s2's type to []int, the compilation will be OK:
package main
import "fmt"
type mySlice1 []int
func main() {
var s1 mySlice1
var s2 []int = s1
fmt.Println(s1, s2)
}
The magic behind it is one rule of assignability:
x's type V and T have identical underlying types and at least one of V or T is not a named type.
References:
Go spec;
Learning Go - Types;
Golang pop quiz.