Search code examples
gotype-safety

Type safety with map, slice or channel types


I wonder why this code compiles in go. I expected a compiler error as I would with e.g. string:

package main

import (
    "fmt"
)

type myMap map[string]int
type mySlice []int
type myChan chan int

type myString string

func main() {
    var mm myMap
    var m map[string]int
    m = mm // fine, but expected compiler error

    var ms mySlice
    var s []int
    s = ms // same with slices

    var mc myChan
    var c chan int
    c = mc // or channels

    var mstr myString
    var str string
//  str = mstr // error, as expected
    fmt.Printf("%T %T %T %T %T %T %T %T\n", mm, m, ms, s, mc, c, mstr, str)
}

Playground
Why don't I get a type mismatch error with those special "reference types" map, slice and chan?


Solution

  • You get no compile-time error in the first 2 cases because those assignments are allowed by the language spec.

    Spec: Assignments:

    In assignments, each value must be assignable to the type of the operand to which it is assigned...

    And Spec: Assignability:

    A value x is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:

    • x's type is identical to T.
    • x's type V and T have identical underlying types and at least one of V or T is not a defined type.
    • T is an interface type and x implements T.
    • x is a bidirectional channel value, T is a channel type, x's type V and T have identical element types, and at least one of V or T is not a defined type.
    • x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type.
    • x is an untyped constant representable by a value of type T.

    The emphasized rule applies to your first 2 cases. It however does not apply to your last case, because both string and myString are defined types. None of the rules apply in your last case.