iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
💊

Practical Guide to Type Constraints in Go Generics: How to Choose the Right Approach

に公開

🚀 Practical Guide to Mastering Go Generics Type Constraints

📝 Introduction

Generics were introduced in Go 1.18 and later.
While they brought convenience, many people find themselves unsure about how to write "type constraints."

The following three points are particularly prone to confusion:

  1. The difference between ~int and ~Hoge
  2. The difference between type Hoge = int and type Hoge int
  3. How to use a marker interface when you want to allow "only types based on Hoge"

This article will clarify each of these points with code examples and explanations, and finally, summarize "How to choose in practice?" as a decision guideline.

📖 Go Generics and Type Constraint Basics

Type Parameters

Go generics is a mechanism that allows "parameterized types to be passed to functions and types."

func PrintAll[T any](values []T) {
    for _, v := range values {
        fmt.Println(v)
    }
}
  • T is a type parameter
  • any is a constraint meaning "any type is OK"

Type Constraints

Type parameters can be constrained to specify "what types can be passed." For example, if you want to allow "only integer-like types":

type Integer interface {
    int | int64 | uint
}

func Sum[T Integer](a, b T) T {
    return a + b
}
  • Integer is the constraint interface
  • int | int64 | uint is the "type set"

Type Sets

Constraint interfaces define the "set of types that can be used."

  • any → All types
  • int | string → int or string
  • ~intAll types whose underlying type is int
  • ~HogeOnly valid if Hoge is an alias

📌 1. Difference between ~int and ~Hoge

~int

Allows "all types whose underlying type is int".

type MyInt int
type Another int

type IntFamily interface {
    ~int
}

👉 OK: int, MyInt, Another

~Hoge

Only valid when Hoge is defined as an alias (type Hoge = int).

type Hoge = int
type Fuga Hoge

type HogeFamily interface {
    ~Hoge
}

👉 OK: int, Hoge, Fuga
👉 NG: Fails if type Hoge int is used

📌 2. Difference between type Hoge = int and type Hoge int

Defined type

type Hoge int
  • Creates a new type
  • Different from int
  • Uses ~int for constraints

Type alias

type Hoge = int
  • An alias for int
  • ~Hoge can be used for constraints
  • Its actual behavior is exactly the same as int

📌 3. Controlling with a marker interface

~int allows for

all int-like types.
If you want to exclude int-based types like Piyo, you can use a marker.

type Hoge int
type Fuga Hoge
type Piyo int // ← Exclude this

type HogeFamily interface {
    ~int
    isHogeFamily()
}

// Implement the marker only for Hoge-related types
func (Hoge) isHogeFamily() {}
func (Fuga) isHogeFamily() {}

👉 This way, only Hoge-related types can be targeted by generics.

🙅‍♂️ Common Misunderstandings and Pitfalls

  • type Hoge int and type Hoge = int are not the same
    → The former creates a "new type," the latter an "alias."

  • ~Hoge is not always usable
    → Only for alias types.

  • Marker interfaces are not magic
    → They are ineffective unless isHogeFamily() is implemented for the type.

📊 How to Choose in Practice (Summary)

What you want to do Recommended way to write Practical Recommendation
Allow all int-like types ~int ✅ Commonly used
Allow only specific series Marker interface 🛠 As needed
Treat as completely identical to int type Hoge = int + ~Hoge ⚠️ Rare case

🎯 Conclusion (Practical Guideline to Avoid Confusion)

  • Start with type Hoge int + ~int as a basic approach.
  • ⚠️ ~Hoge is for special purposes, rarely used in practice.
  • 🛠 Use markers only when you need to control a specific series.

👉 If in doubt, "type Hoge int + ~int" is fine.
Only consider "markers" or "aliases" when you encounter a special situation.


Reading this article will help you quickly recall the decision criteria when you're unsure about generics type constraints.
Please make use of it in your practical implementations.

Discussion