Genéricos
En esta página
Las funciones genéricas reciben uno o más parámetros de tipo entre <>. El
compilador infiere T a partir de los argumentos en la llamada — no es necesario
especificar el tipo explícitamente. Las funciones con múltiples parámetros de tipo
(<A, B>) preservan cada tipo de forma independiente:
identity<T>, head<T> y pair_first<A, B> funcionan con int, str, bool y arrays.
// Feature: Generic functions
// Syntax: `fn name<T>(x: T) -> T { ... }`
// When to use: logic that works with ANY type (identity, containers,
// swaps) preserving the concrete type through the return value.
// Identity — `T` is inferred at the call site.
fn identity<T>(x: T) -> T {
return x
}
print(identity(42)) // 42
print(identity("hi")) // hi
print(identity(true)) // true
// More than one arg of the same `T`.
fn first<T>(a: T, b: T) -> T {
return a
}
print(first(1, 2)) // 1
print(first("a", "b")) // a
// Generic with array.
fn head<T>(arr: [T]) -> T {
return arr[0]
}
print(head([10, 20, 30])) // 10
print(head(["x", "y"])) // x
// Multiple type params.
fn pair_first<A, B>(a: A, b: B) -> A {
return a
}
print(pair_first(7, "right-side")) // 7
// expected:
// 42
// hi
// true
// 1
// a
// 10
// x
// 7
Los structs genéricos almacenan cualquier tipo sin perder la información de
cuál es. El tipo concreto se infiere del literal de construcción. El bloque impl
de un struct genérico incluye el parámetro de tipo:
Box<T>, Pair<A, B> y Stack<T> con impl Stack incluyendo método asociado y de instancia.
// Feature: Generic structs
// Syntax: `struct Name<T> { field: T }`
// When to use: container that holds any type while preserving it.
struct Box<T> {
value: T,
}
// Concrete type comes from usage.
let bi = Box { value: 42 } // Box<int>
let bs = Box { value: "hello" } // Box<str>
print(bi.value) // 42
print(bs.value) // hello
// Multiple type parameters.
struct Pair<A, B> {
first: A,
second: B,
}
let p = Pair { first: 1, second: "one" }
print(p.first) // 1
print(p.second) // one
// `impl` for generic struct — the `<T>` is inferred from the type name.
// NOTE: `len` is dispatched at the runtime level for Array/Map, so we
// expose the size under a distinct name (`size`) to avoid the clash.
struct Stack<T> {
items: [T],
}
impl Stack {
fn make() -> Stack {
return Stack { items: [] }
}
fn size(self) -> int {
return self.items.len()
}
}
let s = Stack::make()
print(s.size()) // 0
Los enums genéricos son la base de los tipos suma parametrizados — el mismo
mecanismo que usa la stdlib para Option<T> y Result<T, E>. El match
desestructura el payload y enlaza la variable al tipo concreto:
Maybe<T> con variantes Just(T) y Nothing; Either<L, R> con dos parámetros.
// Feature: Generic enums
// Syntax: `enum Name<T> { Variant(T), Other }`
// When to use: parameterized sum types — this is how the stdlib
// defines `Option<T>` and `Result<T, E>`.
enum Maybe<T> {
Just(T),
Nothing,
}
// Construction: the `T` type comes from the payload.
let just_int = Maybe.Just(42)
let just_str = Maybe.Just("hello")
let none: Maybe<int> = Maybe.Nothing
let r1 = match just_int {
Maybe::Just(v) => "got {v}",
Maybe::Nothing => "none",
}
print(r1) // got 42
let r2 = match just_str {
Maybe::Just(v) => "got '{v}'",
Maybe::Nothing => "none",
}
print(r2) // got 'hello'
let r3 = match none {
Maybe::Just(v) => "got {v}",
Maybe::Nothing => "none",
}
print(r3) // none
// Result<T, E> with two type parameters.
enum Either<L, R> {
Left(L),
Right(R),
}
let lf = Either.Left("error")
let rt = Either.Right(99)
print(match lf {
Either::Left(s) => "L:{s}",
Either::Right(n) => "R:{n}",
})
// L:error
print(match rt {
Either::Left(s) => "L:{s}",
Either::Right(n) => "R:{n}",
})
// R:99
Desafío
Escribe una función genérica swap<A, B>(a: A, b: B) -> Pair<B, A> que devuelva
los valores en orden invertido. Usa el struct Pair del ejemplo de structs genéricos.
Consulta también