http://www.novanatural.com/products/wooden-shape-sorter

Assignability in Go

Go is statically typed programming language. The set of values allowed to store in variable is determined by the variable’s type. Because of that arbitrary data can’t be just assigned as in dynamically typed language like Python. The rule which is used to govern what is permitted is called assignability.

Having variable left of type T, there are 6 cases when value right can be assigned to left.

1. Identical types

First one is obvious. If right’s type is identical to T then assignment is completely valid. More on this in “Identical types in Go”.

2. Identical underlying types

Each type in Go has an underlying type. For boolean, numeric, string or type literal underlying type is the same as type. Otherwise underlying type is the one from type declaration:

type X map[string]int
var x X  // underlying type is map[string]int

2nd case of assignability is about having identical underlying type:

type X map[string]int
var x X
var y map[string]int
x = y

Having two named types won’t work though:

type X map[string]int
type Y map[string]int
var x X
var y Y
x = y // cannot use y (type Y) as type X in assignment

It’s additionally required that at least one type is not a named type…

Types in Go can be either named or unnamed. Unnamed types are the ones specified using a type literal:

var a [10]string
var b struct{ field string}
var c map[string]int

3. Assigning to interface type T value implementing T

If variable implements interface T then we can assign it to variable of interface type T.

type Callable interface {
f() int
}
type T int
func (t T) f() int {
return int(t)
}
var c Callable
var t T
c = t

More on interface types in language spec.

4. Assigning bidirectional channel to variable with identical element types

type T chan<- map[string]int
var c1 T
var c2 chan map[string]int
c1 = c2
c2 = c1 // cannot use c1 (type T) as type chan map[string]int in assignment

As with with 2nd case (identical underlying types) at least one channel type must be unnamed type:

type T chan<- map[string]int
type T2 chan map[string]int
var c1 T
var c2 T2
c1 = c2 // cannot use c2 (type T2) as type T in assignment

5. Assigning nil

It’s allowed to assign nil to variable which is a pointer, function, slice, map, channel or interface type.

var a *int
var b func(int) int
var c []int
var d map[string]int
var e chan int
var f interface{}
a, b, c, d, e, f = nil, nil, nil, nil, nil, nil
var g [10]int
g = nil // cannot use nil as type [10]int in assignment

6. Untyped constants

Great in-depth introduction to Go constants can be found on official blog.

Untyped constant can be set to variable of type T if constant is representable by value of type T.

var a float32
var b float64
var c int32
var d int64
const untyped = 1
a = untyped
b = untyped
c = untyped
d = untyped

Resources