06 · Funciones
Lambdas y funciones anónimas
Funciones anónimas con |args| expr y capturas de ámbito léxico.
En esta página
Una lambda es una función sin nombre, escrita como |params| expr o
|params| { bloque }. Las lambdas son valores de primera clase: pueden
asignarse a variables, pasarse como argumento y devolverse desde funciones:
Forma corta, forma tipada, forma de bloque y lambda sin parámetros (thunk).
// Feature: Anonymous functions (lambdas)
// Syntax: `|a, b| expr` or `|a: T| { ... }` (block body)
// When to use: short callbacks, inline function values,
// functional composition without naming each step.
// Short form: body is a single expression.
let double = |x| x * 2
let add = |a, b| a + b
print(double(5)) // 10
print(add(3, 4)) // 7
// Parameters can be explicitly typed.
let mul: fn(int, int) -> int = |a: int, b: int| a * b
print(mul(6, 7)) // 42
// Block form — multiple lines, requires `return`.
let process = |x: int| {
let doubled = x * 2
let plus_one = doubled + 1
return plus_one
}
print(process(10)) // 21
// Lambdas are values: pass them as arguments.
fn apply(f: fn(int) -> int, x: int) -> int {
return f(x)
}
print(apply(|n| n * n, 9)) // 81
// Lambda without parameters — useful for a "thunk" (lazy value).
let now = || 42
print(now()) // 42
Cuando una lambda se crea dentro de una función, captura las variables del ámbito externo por su valor vinculado — esto la convierte en una closure. Cada llamada a la función fabrica una closure independiente:
make_adder, make_formatter — cada closure lleva su propio estado inmutable capturado.
// Feature: Closures — lambdas that capture lexical scope
// Syntax: `|args| body` inside an fn — captures `let`
// and `let mut` that are visible.
// When to use: remember configuration, create functions with
// embedded state, close over local helpers.
use std::Array
// Capturing a constant from the outer scope.
fn make_adder(n: int) {
return |x| x + n // captures `n`
}
let add5 = make_adder(5)
let add10 = make_adder(10)
print(add5(3)) // 8
print(add10(3)) // 13
// Each call creates an independent closure.
let addA = make_adder(100)
let addB = make_adder(200)
print(addA(1)) // 101
print(addB(1)) // 201
// Closures can capture multiple variables.
fn make_formatter(prefix: str, suffix: str) {
return |s| prefix + s + suffix
}
let bracket = make_formatter("[", "]")
let bold = make_formatter("**", "**")
print(bracket("ok")) // [ok]
print(bold("warning")) // **warning**
// Closures naturally combine with higher-order.
let nums = [1, 2, 3, 4, 5]
let threshold = 3
let big = nums.filter(|x| x > threshold)
print(big) // [4, 5]
Una lambda corta puede combinar accesos al mismo parámetro implícito:
users.filter(_.active && _.age >= 18). Las variables locales se capturan
normalmente. Cada argumento de una llamada anidada tiene su propio ámbito;
usa |user| check(user.age) para pasar la edad a otra función.
Los accesos con _ comparten un parámetro; los predicados y las transformaciones aritméticas conservan los tipos del contexto.
// Short lambdas share one parameter across the argument's rooted accesses.
struct User { name: str, age: int, active: bool }
struct Line { price: int, quantity: int }
fn main() {
let users = [
User { name: "Ada", age: 36, active: true },
User { name: "Bo", age: 17, active: true },
User { name: "Cy", age: 24, active: false },
]
print(users.filter(_.active && _.age >= 18).map(_.name))
// expected: [Ada]
let lines = [Line { price: 3, quantity: 4 }, Line { price: 5, quantity: 2 }]
print(lines.map(_.price * _.quantity))
// expected: [12, 10]
let adjustment = 2
print(lines.map(_.price + adjustment))
// expected: [5, 7]
}
Desafío
Escribe make_multiplier(factor: int) que devuelva una lambda que multiplique
por factor. Crea doble y triple y aplícalos a [1, 2, 3, 4, 5] con .map().
Fijar argumentos una vez
La aplicación parcial guarda los argumentos fijos al crear la función. Cada underscore se convierte en una entrada independiente de la nueva función.
// Fixed arguments are acquired once; each underscore is an input of the new function.
var acquisitions = 0
fn initial() -> int { acquisitions += 1; 10 }
fn add(base: int, amount: int) -> int { base + amount }
let add_initial = partial add(initial(), _)
print(add_initial(5)) // expect: 15
print(add_initial(8)) // expect: 18
print(acquisitions) // expect: 1
fn subtract(left: int, right: int) -> int { left - right }
let remaining = partial subtract(right: _, left: 20)
print(remaining(3)) // expect: 17
Elegir los valores capturados
El encabezado de captura elige los valores antes de crear la closure. Un cambio posterior en la variable externa no modifica el nombre capturado.
// The closure uses the price chosen at construction, even after it changes.
var unit_price = 5
let quote = capture { price: unit_price } |quantity: int| price * quantity
unit_price = 9
print(quote(3)) // expect: 15
print(unit_price) // expect: 9
Consulta también