Go Interface Type Constraints – Conversion Issues Explained

constraintsgenericsgotype-parameter

type Number interface {
    int | int64 | float64
}

type NNumber interface {
}

//interface contains type constraints
//type NumberSlice []Number

type NNumberSlice []NNumber

func main() {
    var b interface{}
    b = interface{}(1)
    fmt.Println(b)

    // interface contains type constraints
    // cannot use interface Number in conversion (contains specific type constraints or is comparable)
    //a := []Number{Number(1), Number(2), Number(3), Number(4)}
    //fmt.Println(a)

    aa := []interface{}{interface{}(1), interface{}(2), interface{}(3), 4}
    fmt.Println(aa)

    aaa := []NNumber{NNumber(1), NNumber(2), NNumber(3), 4}
    fmt.Println(aaa)
}

why the Number slice a couldn't be initialized like that?

NumberSlice and NNumberSlice look like similarly, but what mean type constraints, it looks strange grammar

Best Answer

The language specifications explicitly disallow using interfaces with type elements as anything other than type parameter constraints (the quote is under the paragraph Interface types):

Interfaces that are not basic may only be used as type constraints, or as elements of other interfaces used as constraints. They cannot be the types of values or variables, or components of other, non-interface types.

An interface that embeds comparable or another non-basic interface is also non-basic. Your Number interface contains a union, hence it is non-basic too.

A few examples:

// basic: only methods
type A1 interface {
    GetName() string
}

// basic: only methods and/or embeds basic interface
type B1 interface {
    A1
    SetValue(v int)
}

// non-basic: embeds comparable
type Message interface {
    comparable
    Content() string
}

// non-basic: has a type element (union)
type Number interface {
    int | int64 | float64
}

// non-basic: embeds a non-basic interface
type SpecialNumber interface {
    Number
    IsSpecial() bool
}

In the initialization of the variable a, you are attempting to use Number in a type conversion Number(1), and this is not allowed.

You can only use Number as a type parameter constraint, i.e. to restrict the types allowed for instantiation of a generic type or function. For example:

type Coordinates[T Number] struct {
    x, y T
}

func sum[T Number](a, b T) T {
    return a + b
}
Related Question