gogenericsconstraintstype-parameter

interface contains type constraints: cannot use interface in conversion


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


Solution

  • 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
    }