or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

apidiff.mdconstraints.mdebnf.mderrors.mdevent.mdgorelease.mdindex.mdio-i2c.mdio-spi.mdjsonrpc2.mdmaps.mdmmap.mdmodgraphviz.mdrand.mdshiny.mdslices.mdslog.mdstats.mdsumdb.mdtrace.mdtxtar.mdtypeparams.mdutf8string.md
tile.json

constraints.mddocs/

golang.org/x/exp/constraints

Package constraints provides a set of useful constraint interfaces to be used with Go generic type parameters. These constraints enable generic functions to work with specific categories of types, such as signed integers, floating-point numbers, or any ordered types.

Package Information

  • Package Name: golang.org/x/exp/constraints
  • Package Type: Go (golang)
  • Language: Go
  • Installation: go get golang.org/x/exp/constraints

Core Imports

import (
	"golang.org/x/exp/constraints"
)

Alternative import pattern for specific constraints:

import (
	"golang.org/x/exp/constraints"
)

// Use in type parameters
func Max[T constraints.Ordered](a, b T) T {
	if a < b {
		return b
	}
	return a
}

Basic Usage

package main

import (
	"fmt"
	"golang.org/x/exp/constraints"
)

// Generic function that works with any signed integer
func AddSigned[T constraints.Signed](a, b T) T {
	return a + b
}

// Generic function that works with any floating-point type
func MaxFloat[T constraints.Float](a, b T) T {
	if a > b {
		return a
	}
	return b
}

// Generic function that works with any ordered type
func Min[T constraints.Ordered](a, b T) T {
	if a < b {
		return a
	}
	return b
}

func main() {
	// Signed integers
	result1 := AddSigned(int32(5), int32(3))
	fmt.Println(result1) // 8

	// Floating-point types
	result2 := MaxFloat(3.14, 2.71)
	fmt.Println(result2) // 3.14

	// Ordered types (string)
	result3 := Min("apple", "banana")
	fmt.Println(result3) // apple
}

Capabilities

Signed Integer Constraint

Permits any signed integer type. Useful for generic functions that need to work with signed integers of any size.

type Signed interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64
}

The Signed constraint permits any signed integer type. If future releases of Go add new predeclared signed integer types, this constraint will be modified to include them.

Use case: Generic functions performing arithmetic operations or comparisons on signed integer values.

Example:

func Sum[T constraints.Signed](values ...T) T {
	var total T
	for _, v := range values {
		total += v
	}
	return total
}

// Works with any signed integer type
sum := Sum(int64(1), int64(2), int64(3))

Unsigned Integer Constraint

Permits any unsigned integer type. Useful for generic functions working with unsigned integers or bitwise operations.

type Unsigned interface {
	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

The Unsigned constraint permits any unsigned integer type. If future releases of Go add new predeclared unsigned integer types, this constraint will be modified to include them.

Use case: Generic functions handling unsigned values, memory offsets, or bit manipulation.

Example:

func IsPowerOfTwo[T constraints.Unsigned](n T) bool {
	return n > 0 && (n&(n-1)) == 0
}

// Works with any unsigned integer type
isPower := IsPowerOfTwo(uint32(16))

Integer Constraint

Permits any integer type (both signed and unsigned). This is a composite constraint combining Signed and Unsigned.

type Integer interface {
	Signed | Unsigned
}

The Integer constraint permits any integer type. If future releases of Go add new predeclared integer types, this constraint will be modified to include them.

Use case: Generic functions that need to work with any integer type regardless of signedness.

Example:

func Abs[T constraints.Integer](n T) T {
	if n < 0 {
		return -n
	}
	return n
}

// Works with both signed and unsigned integers
absValue := Abs(int32(-42))

Float Constraint

Permits any floating-point type. Useful for generic functions performing mathematical operations on float types.

type Float interface {
	~float32 | ~float64
}

The Float constraint permits any floating-point type. If future releases of Go add new predeclared floating-point types, this constraint will be modified to include them.

Use case: Generic mathematical functions, statistical calculations, or scientific computations.

Example:

func Average[T constraints.Float](values ...T) T {
	var sum T
	for _, v := range values {
		sum += v
	}
	return sum / T(len(values))
}

// Works with any floating-point type
avg := Average(3.14, 2.71, 1.41)

Complex Constraint

Permits any complex numeric type. Useful for generic functions working with complex numbers.

type Complex interface {
	~complex64 | ~complex128
}

The Complex constraint permits any complex numeric type. If future releases of Go add new predeclared complex numeric types, this constraint will be modified to include them.

Use case: Generic functions for complex number arithmetic, signal processing, or advanced mathematical operations.

Example:

func Magnitude[T constraints.Complex](c T) float64 {
	r := real(c)
	i := imag(c)
	return math.Sqrt(r*r + i*i)
}

// Works with any complex type
mag := Magnitude(complex(3, 4))

Ordered Constraint

Permits any ordered type - any type that supports the comparison operators (<, <=, >=, >). This constraint enables sorting and minimum/maximum operations on any comparable ordered type.

type Ordered = cmp.Ordered

The Ordered constraint permits any ordered type. If future releases of Go add new ordered types, this constraint will be modified to include them.

Note: This type is redundant since Go 1.21 introduced cmp.Ordered. For Go 1.21+, prefer using cmp.Ordered directly.

Use case: Generic functions for sorting, finding minimum/maximum values, or other operations requiring ordering.

Example:

func Max[T constraints.Ordered](a, b T) T {
	if a > b {
		return a
	}
	return b
}

func Min[T constraints.Ordered](a, b T) T {
	if a < b {
		return a
	}
	return b
}

// Works with strings, numbers, or any comparable type
maxStr := Max("apple", "zebra")
maxInt := Max(10, 20)
minFloat := Min(3.14, 2.71)

Constraint Relationships

The constraints in this package form the following hierarchy:

  • Integer = Signed | Unsigned
    • Signed: int, int8, int16, int32, int64
    • Unsigned: uint, uint8, uint16, uint32, uint64, uintptr
  • Float: float32, float64
  • Complex: complex64, complex128
  • Ordered: Any type supporting <, <=, >=, > operators

Complete API

package constraints // import "golang.org/x/exp/constraints"

// Signed is a constraint that permits any signed integer type.
type Signed interface {
	~int | ~int8 | ~int16 | ~int32 | ~int64
}

// Unsigned is a constraint that permits any unsigned integer type.
type Unsigned interface {
	~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
}

// Integer is a constraint that permits any integer type (signed or unsigned).
type Integer interface {
	Signed | Unsigned
}

// Float is a constraint that permits any floating-point type.
type Float interface {
	~float32 | ~float64
}

// Complex is a constraint that permits any complex numeric type.
type Complex interface {
	~complex64 | ~complex128
}

// Ordered is a constraint that permits any ordered type.
// This is equivalent to cmp.Ordered and is redundant in Go 1.21+.
type Ordered = cmp.Ordered

Advanced Usage Examples

Type-based Function Selection

// Clamp constrains a value to a range
func Clamp[T constraints.Ordered](value, min, max T) T {
	if value < min {
		return min
	}
	if value > max {
		return max
	}
	return value
}

// Usage
clampedInt := Clamp(5, 1, 10)      // 5
clampedStr := Clamp("b", "a", "c") // "b"

Combining Multiple Constraints

// Some types might satisfy multiple constraints
// Use union syntax for functions needing specific types

// Function for numeric types that can be ordered
func LinearInterpolate[T constraints.Float](a, b, t T) T {
	return a*(1-t) + b*t
}

// Function for any comparable type
func Contains[T constraints.Ordered](slice []T, value T) bool {
	for _, v := range slice {
		if v == value {
			return true
		}
	}
	return false
}

Using Type Parameters with Constraints

// Calculate statistical measures
func Variance[T constraints.Float](values []T) T {
	if len(values) == 0 {
		return 0
	}

	var mean T
	for _, v := range values {
		mean += v
	}
	mean /= T(len(values))

	var variance T
	for _, v := range values {
		diff := v - mean
		variance += diff * diff
	}
	variance /= T(len(values))

	return variance
}

// Calculate magnitude of complex numbers
func Conjugate[T constraints.Complex](c T) T {
	return T(complex(real(c), -imag(c)))
}

Common Patterns

Type Switch Alternative

Instead of using type switches, you can use constraints to handle multiple types generically:

// Without constraints (type switch)
func PrintValue(v interface{}) {
	switch val := v.(type) {
	case int:
		fmt.Println("int:", val)
	case float64:
		fmt.Println("float:", val)
	case string:
		fmt.Println("string:", val)
	}
}

// With constraints (generic)
func PrintValue[T constraints.Ordered](v T) {
	fmt.Println("value:", v)
}

Mixing Constraints in Generic Functions

// Define custom constraint combinations as needed
type Numeric interface {
	constraints.Integer | constraints.Float
}

func Square[T Numeric](value T) T {
	return value * value
}

// Works with any integer or float type
sqInt := Square(int32(5))    // 25
sqFloat := Square(3.5)       // 12.25

Notes and Considerations

  • Backward Compatibility: These constraints may be updated if Go adds new built-in numeric types. Code using these constraints remains compatible.
  • Tilde (~) Operator: The ~ in constraint definitions allows named types whose underlying type matches. For example, a custom type MyInt with underlying type int satisfies the Signed constraint.
  • Go 1.21+ Migration: The Ordered constraint is redundant in Go 1.21 and later. Use cmp.Ordered from the standard library instead for new code.
  • Performance: Constraints are compile-time constructs and have zero runtime overhead. Generic functions with constraints are as fast as manually written type-specific functions.