Interfaces as type constraints

May 5, 2023

If you’ve been playing around with interface types while reading about them for the last couple of weeks, you have probably noticed something: Many of the interface types described don’t work as variables. Here we see why:

General interfaces

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.

var x Float                     // illegal: Float is not a basic interface

var x interface{} = Float(nil)  // illegal

type Floatish struct {
	f Float                 // illegal
}

This makes for a potentially confusing situation: We can define a type that cannot be used as a variable.

So then what’s the point of such a type?

Well, they’re useful as type constraints in generic functions which, we’ll dig into later. But as a preview/refresher, here’s what that looks like:

type Int interface {
	int | int8 | int16 | int32 | uint | uint8 | uint16 | uint32
}

func add[T Int](a, b T) T {
	return a + b
}

So if that Int type cannot represent a variable, then of what type are the arguments a and b inside the above function?

Well, that depends on the type passed into the function! Let’s add a bit of debugging output to the function:

func add[T Int](a, b T) T {
	fmt.Printf("%T\n", a) // %T prints the argument's type
	return a + b
}

Now let’s call it with different input types and see what it does:

add(int(3), int(4))     // Prints: int
add(int32(5), int32(6)) // Prints: int32

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


Share this

Direct to your inbox, daily. I respect your privacy .

Unsure? Browse the archive .

Related Content


Satisfying a type constraint

Satisfying a type constraint A type argument T satisfies a type constraint C if T is an element of the type set defined by C; i.e., if T implements C. As an exception, a strictly comparable type constraint may also be satisfied by a comparable (not necessarily strictly comparable) type argument. More precisely: A type T satisfies a constraint C if T implements C; or C can be written in the form interface{ comparable; E }, where E is a basic interface and T is comparable and implements E.


Type constraints

Are you as curious about Fuzzing in Go as I am? On Monday’s live stream, I’ll be live coding my way through John Arundel’s 4-part series on Go Fuzzing. I hope you’ll [join me!](https://youtube.com/live/VKV-sFFeSQw Type constraints A type constraint is an interface that defines the set of permissible type arguments for the respective type parameter and controls the operations supported by values of that type parameter. TypeConstraint = TypeElem . If the constraint is an interface literal of the form interface{E} where E is an embedded type element (not a method), in a type parameter list the enclosing interface{ … } may be omitted for convenience:


Comparison operators, part III

Today we continue through the list of data types and how comparison and ordering works on each. Comparison operators … Channel types are comparable. Two channel values are equal if they were created by the same call to make or if both have value nil. Notice that channel comparison is effectively a comparison of identity. Not type or content. Two channels may have the same type and contents, but be unequal: