Type Parameters
Part of the Object Oriented Programming section of Coddy's GO journey — lesson 68 of 107.
Type parameters are the placeholders you declare in square brackets that allow your functions and types to work with different concrete types. Understanding how to declare and use them is fundamental to writing generic code in Go.
A type parameter is declared between the function name and its regular parameters. You give it a name (conventionally a single uppercase letter) and specify what types it can accept:
func Print[T any](value T) {
fmt.Println(value)
}Here, T is the type parameter and any means it accepts any type. When you call this function, Go infers the type from the argument:
Print(42) // T is inferred as int
Print("hello") // T is inferred as string
Print(3.14) // T is inferred as float64You can also explicitly specify the type parameter when calling the function:
Print[int](42)
Print[string]("hello")Functions can have multiple type parameters, separated by commas:
func Pair[K, V any](key K, value V) {
fmt.Printf("Key: %v, Value: %v\n", key, value)
}
Pair("name", 25) // K=string, V=int
Pair(1, true) // K=int, V=boolThe type parameter can be used anywhere a regular type would appear—as parameter types, return types, or within the function body. This flexibility makes generic functions powerful tools for writing reusable code.
Challenge
EasyLet's build a data transformation toolkit using generic functions with multiple type parameters! You'll create utility functions that can work with different combinations of types, demonstrating how type parameters make your code flexible and reusable.
You'll organize your code across two files:
transform.go: Define your generic transformation functions.Create a generic function
Swap[A, B any](first A, second B) (B, A)that takes two values of potentially different types and returns them in reversed order.Create a generic function
Repeat[T any](value T, count int) []Tthat creates a slice containing the given value repeatedcounttimes.Create a generic function
First[T any](items []T) Tthat returns the first element of a slice. You can assume the slice will always have at least one element.main.go: Read input and demonstrate your generic functions with various type combinations.Read an operation type, then perform the corresponding action:
- For
swap: Read a string and an integer, callSwap, and print the results showing the swapped order - For
repeat: Read a value type (stringorint), the value itself, and a count. Print each repeated element on its own line - For
first: Read a type (stringorint), a count, then that many values. Print the first element
- For
The following inputs will be provided:
- Line 1: Operation type (
swap,repeat, orfirst) - Following lines depend on the operation (see examples below)
For a swap operation with inputs:
swap
hello
42Your output should be:
Swapped: 42, helloFor a repeat operation with inputs:
repeat
string
Go
3Your output should be:
Go
Go
GoFor a first operation with inputs:
first
int
4
10
20
30
40Your output should be:
First: 10Notice how Swap uses two different type parameters [A, B any] allowing it to accept values of different types, while Repeat and First use a single type parameter to work with any type consistently.
Cheat sheet
Type parameters are placeholders declared in square brackets that allow functions to work with different concrete types.
A type parameter is declared between the function name and its regular parameters:
func Print[T any](value T) {
fmt.Println(value)
}Here, T is the type parameter and any means it accepts any type.
Go infers the type from the argument when calling the function:
Print(42) // T is inferred as int
Print("hello") // T is inferred as string
Print(3.14) // T is inferred as float64You can explicitly specify the type parameter:
Print[int](42)
Print[string]("hello")Functions can have multiple type parameters, separated by commas:
func Pair[K, V any](key K, value V) {
fmt.Printf("Key: %v, Value: %v\n", key, value)
}
Pair("name", 25) // K=string, V=int
Pair(1, true) // K=int, V=boolType parameters can be used as parameter types, return types, or within the function body.
Try it yourself
package main
import (
"bufio"
"fmt"
"os"
"strconv"
)
func main() {
scanner := bufio.NewScanner(os.Stdin)
// Read operation type
scanner.Scan()
operation := scanner.Text()
switch operation {
case "swap":
// Read a string and an integer
scanner.Scan()
strVal := scanner.Text()
scanner.Scan()
intVal, _ := strconv.Atoi(scanner.Text())
// TODO: Call Swap and print the results
// Output format: "Swapped: <second>, <first>"
case "repeat":
// Read value type, value, and count
scanner.Scan()
valueType := scanner.Text()
scanner.Scan()
value := scanner.Text()
scanner.Scan()
count, _ := strconv.Atoi(scanner.Text())
// TODO: Based on valueType ("string" or "int"), call Repeat
// and print each element on its own line
_ = valueType
_ = value
_ = count
case "first":
// Read type and count
scanner.Scan()
elemType := scanner.Text()
scanner.Scan()
count, _ := strconv.Atoi(scanner.Text())
// TODO: Read 'count' values, build a slice, call First
// Output format: "First: <value>"
_ = elemType
_ = count
}
}
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Object Oriented Programming
1Fundamentals of Go OOP
External FilesGo Workspace & ModulesPackages & ImportsExported vs Unexported NamesIntroduction to OOP in GoStructs as ClassesDefining Methods on StructsPointer vs Value ReceiversStruct InitializationConstructor FunctionsRecap - Simple Calculator4Interfaces
Introduction to InterfacesImplicit ImplementationInterface as ContractEmpty Interface (any)Type AssertionType SwitchInterface CompositionStringer & Error InterfacesRecap - Shape Calculator7Encapsulation
Exported vs Unexported FieldsPackage-Level EncapsulationGetter & Setter MethodsInformation Hiding in GoRecap - Student Records10Generics (Go 1.18+)
Introduction to GenericsType ParametersType ConstraintsGeneric StructsGeneric Methods WorkaroundRecap - Generic Collection2Types & Structs Deep Dive
Basic & Composite TypesCustom Type DefinitionsStruct TagsAnonymous StructsNested StructsZero Values & DefaultsRecap - Contact Book5Composition Over Inheritance
Why Go Has No InheritanceStruct Embedding BasicsMethod PromotionEmbedding Multiple StructsEmbedding vs AggregationShadowing Embedded MethodsRecap - Employee Hierarchy8Error Handling & OOP
The error InterfaceCustom Error TypesError Wrapping (fmt.Errorf)Sentinel Errorserrors.Is() and errors.As()Panic, Defer, and RecoverRecap - File Parser3Pointers & Memory
Pointer Basics in GoPointers to StructsPass by Value vs ReferenceThe new() FunctionGarbage Collection in GoRecap - Linked List Builder6Polymorphism in Go
Polymorphism via InterfacesDuck Typing in GoInterface Satisfaction RulesPolymorphic CollectionsDependency InjectionRecap - Payment Processor9Concurrency & OOP
Goroutines BasicsChannels & CommunicationBuffered vs Unbuffered ChanSelect Statementsync.Mutex & sync.RWMutexsync.WaitGroupThread-Safe Struct DesignRecap - Worker Pool