Generics

19.1 Generic Functions

Since V 0.4, generics use square brackets [T]. Older code used <T>.

fn max_of[T](a T, b T) T {
	return if a > b { a } else { b }
}

fn find[T](arr []T, x T) ?int {
	for i, v in arr {
		if v == x { return i }
	}
	return none
}

println(max_of(3, 7))
println(max_of('a', 'b'))
println(max_of[f64](1.5, 2.5))     // explicit type argument
println(find([1, 2, 3], 2) or { -1 })

19.2 Generic Structs

struct Stack[T] {
mut:
	items []T
}

fn (mut s Stack[T]) push(x T) { s.items << x }
fn (mut s Stack[T]) pop() ?T {
	if s.items.len == 0 { return none }
	return s.items.pop()
}
fn (s Stack[T]) is_empty() bool { return s.items.len == 0 }

mut st := Stack[int]{}
st.push(1)
st.push(2)
println(st.pop() or { 0 })

struct Pair[K, V] {
	key K
	val V
}
p := Pair[string, int]{'age', 30}

19.3 Generic Constraints and Compile-Time Checks

Interfaces can act as constraints (pass the interface type). Comptime $if T is ... handles type-specific paths.

fn sum[T](nums []T) T {
	mut total := T(0)
	for n in nums { total += n }
	return total
}

fn describe[T](x T) string {
	$if T is int { return 'int' }
	$else $if T is string { return 'string' }
	$else $if T is $struct { return 'struct ${T.name}' }
	return 'other'
}