Restrictions on underlying type terms

April 27, 2023

General interfaces

In a term of the form ~T, the underlying type of T must be itself, and T cannot be an interface.

type MyInt int

interface {
	~[]byte  // the underlying type of []byte is itself
	~MyInt   // illegal: the underlying type of MyInt is not MyInt
	~error   // illegal: error is an interface
}

Once again, the spec examples are pretty well explained. TL;DR; the ~ prefix must always be associated with an underlying data type.

Not explicitly mentioned here, though still important, you can use a struct as the underlying type, but not a named struct. That is, you must use an anonymous struct, which can get quite verbose:

type Person {
	Name string
	Age  int
}

interface {
	Person // Valid

	~Person // illegal: underlying type of MyStruct is struct{Name string; Age int}

	~struct{Name string; Age int} // Valid
}

Quotes from The Go Programming Language Specification Version of December 15, 2022

Share this

Related Content

Underlying types

We’ve made it through the complete list of types in Go. Now we’re going to dig into some of the fundamentals, with a tour of general “Properties of types and values”. Properties of types and values Underlying types Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T’s underlying type is the underlying type of the type to which T refers in its declaration.

Interface examples with type elements

Let’s look at some interface examples from the spec: General interfaces … // An interface representing only the type int. interface { int } // An interface representing all types with underlying type int. interface { ~int } // An interface representing all types with underlying type int that implement the String method. interface { ~int String() string } // An interface representing an empty type set: there is no type that is both an int and a string.

Interfaces don't contain interfaces

As we learned recently, Go interface elements may contain a type term of a non-interface type. It’s worth re-iterating that these are non-interface types. In particular, as the spec states: General interfaces … By construction, an interface’s type set never contains an interface type. That is to say, that the following is invalid: type interface foo { /* some interface elements */ } type interface bar { foo } Actually, I lied.