Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.syntblaze.com/llms.txt

Use this file to discover all available pages before exploring further.

A type parameter in Go is a compile-time placeholder for a concrete type, enabling generic programming. Declared within square brackets [], type parameters allow functions, custom types, and methods to operate over a defined set of types while maintaining strict, compile-time type safety, eliminating the need for interface{} and runtime type assertions.

Syntax

Type parameters are defined in a type parameter list, which appears immediately after the name of a function or type. Each parameter must be paired with a type constraint. Function Declaration:
func FunctionName[T Constraint](param T) T {
    // ...
}
Custom Type Declaration:
type TypeName[T1 ConstraintA, T2 ConstraintB] struct {
    Field1 T1
    Field2 T2
}

Core Components

1. Type Constraints

Every type parameter must be bounded by a constraint. A constraint is an interface that dictates which concrete types are permitted as arguments and what operations can be performed on the type parameter.
  • any: An alias for interface{}, permitting any type. No operations (like + or ==) are guaranteed.
  • comparable: A built-in interface restricting the parameter to types that support the == and != operators (e.g., booleans, numbers, strings, pointers, channels, and structs composed of comparable types).
  • Type Sets: Constraints can define a specific union of types using the | operator. The ~ token specifies that the constraint applies to the underlying type, allowing custom-defined types to satisfy the constraint.
// Constraint defining a type set of underlying integers or floats
type Numeric interface {
    ~int | ~float64
}

func Add[T Numeric](a, b T) T {
    return a + b // Valid because the Numeric constraint guarantees the + operator
}

2. Type Arguments and Instantiation

When a generic function or type is used, the type parameters are replaced by type arguments (concrete types like int or string). This two-step process is called instantiation:
  1. The compiler substitutes the type arguments for the type parameters throughout the generic declaration.
  2. The compiler verifies that each type argument satisfies its corresponding constraint.
type Container[T any] []T

// Explicit instantiation
var intContainer Container[int] = []int{1, 2, 3}

3. Type Inference

To reduce verbosity, the Go compiler performs type inference during function calls. If the type arguments can be unambiguously deduced from the regular function arguments, the explicit type parameter list can be omitted at the call site.
func Print[T any](value T) { /* ... */ }

// Explicit type argument
Print[string]("Hello")

// Inferred type argument (T is inferred as string)
Print("Hello")

Method Receivers

Methods can be declared on generic types. The receiver must list the type parameters defined by the base type, but it must omit the constraints. The parameter names themselves can differ from the original type definition, but the number of parameters must match. Methods cannot declare new type parameters; they can only utilize the type parameters defined by their receiver type.
type Box[T any] struct {
    Value T
}

// The receiver omits the constraint (uses *Box[T], not *Box[T any])
func (b *Box[T]) Get() T {
    return b.Value
}
Master Go with Deep Grasping Methodology!Learn More