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]intvar x X // underlying type is map[string]int
2nd case of assignability is about having identical underlying type:
type X map[string]intvar 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]intvar 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 intfunc (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]intvar 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]intvar 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, nilvar 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 int64const untyped = 1
a = untyped
b = untyped
c = untyped
d = untyped