Guía 12 de 53
Parámetros de funciones y lambdas
Lambdas, etiquetas, bloques de callback y cláusulas por patrón.
En esta página
Lambdas, etiquetas, bloques de callback y cláusulas por patrón.
Lambdas cortas de predicado¶
Los accesos desde underscore usan el mismo parámetro implícito. Combina campos, cálculos y pruebas booleanas; usa una lambda explícita si el alcance resulta ambiguo.
Practica en By Example · Programa fuente
// 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]
}Argumentos nombrados abreviados¶
Una llamada con name: pasa la variable name del llamador. Puedes mezclar valores explícitos y abreviados y reordenarlos por etiqueta. Una variable ausente es un error; el formateador conserva la abreviatura.
Practica en By Example · Programa fuente
// Named argument shorthand keeps the label and uses the local value.
struct User {
name: str,
email: str,
active: bool,
}
fn create_user(name: str, email: str, active: bool = true) -> User {
User { name, email, active }
}
struct Team {
title: str,
}
impl Team {
fn contact(self, name: str, email: str) -> str {
"{self.title}: {name} <{email}>"
}
}
fn main() {
let name = "Ana"
let email = "ana@example.com"
// Reordering and defaults are the same as for explicit named arguments.
let user = create_user(email:, name:)
print("{user.name} <{user.email}>") // expected: Ana <ana@example.com>
print(user.active) // expected: true
// Explicit values and shorthand can be mixed.
let disabled = create_user(name:, email:, active: false)
print(disabled.active) // expected: false
let team = Team { title: "Zolo" }
print(team.contact(email:, name:)) // expected: Zolo: Ana <ana@example.com>
}Funciones con cuerpo de expresión¶
Usa = expresión en una función o método pequeño. La expresión proporciona el retorno; return, propagación de Result, genéricos y valores por defecto conservan la semántica de un cuerpo en bloque.
Practica en By Example · Programa fuente
// Feature: Expression-bodied functions and methods
// Syntax: fn name(parameters) -> Type = expression
// When to use: a small calculation, branch, forwarding call or method.
fn double(x: int) -> int = x * 2
fn absolute(x: int) -> int = if x < 0 { -x } else { x }
fn increment(value: int = 3) -> int = value + 1;
fn identity<T>(value: T) -> T = value
struct Counter(value: int) {
fn next(self) -> int = self.value + 1
}
fn read_positive(value: int) -> Result<int, str> =
if value > 0 { .Ok(value) } else { .Err("positive value required") }
// Question-mark failures exit this function; success is explicitly wrapped.
fn checked_double(value: int) -> Result<int, str> = .Ok(double(read_positive(value)?))
print(double(4)) // expected: 8
print(absolute(-7)) // expected: 7
print(increment()) // expected: 4
print(identity("Ada")) // expected: Ada
let counter: Counter = .{ value: 9 }
print(counter.next()) // expected: 10
match checked_double(5) {
.Ok(value) => print(value),
.Err(error) => print(error)
} // expected: 10
match checked_double(-1) {
.Ok(value) => print(value),
.Err(error) => print(error)
} // expected: positive value requiredBloques finales nombrados¶
Varios callbacks pueden aparecer después de la llamada como bloques etiquetados. Las etiquetas resuelven parámetros de función y permiten otro orden. Crear el callback no ejecuta su cuerpo; las capturas mutables conservan sus celdas.
Practica en By Example · Programa fuente
// Several callbacks read in the order of the operation they describe.
fn dialog(title: str, content: fn() -> str, confirm: fn() -> bool) -> str {
let message = content()
if confirm() { "{title}: {message}" } else { "{title}: cancelled" }
}
let answer = dialog(title: "Delete?") content {
"This removes one file."
} confirm {
true
}
print(answer)
// expected: Delete?: This removes one file.
fn transform(value: int, before: fn(int) -> int, finish: fn(int) -> int) -> int {
finish(before(value))
}
print(transform(3) finish { |value| value * 2 } before { |value| value + 1 })
// expected: 8
// Creating a callback does not run its body. Mutable captures keep their cell.
var calls = 0
fn invoke(work: fn() -> int) -> int = work()
print(invoke() work { calls += 1; calls })
// expected: 1
print(calls)
// expected: 1Etiquetas externas de argumentos¶
Separa la etiqueta pública del nombre local del parámetro: from source: int. El llamador usa from: y la función lee source. Las etiquetas forman parte de la interfaz y se conservan en valores de función.
Practica en By Example · Programa fuente
// expected: 12
// expected: 3
// expected: 15
// expected: 9
// expected: 18
// expected: 2
fn travel(from source: int, to destination: int, by step: int = 1) -> int =
(destination - source) * step
let from = 2
let to = 8
print(travel(to:, from:, by: 2))
print(travel(1, 4))
fn choose(with transform: fn(int) -> int, on value: int) -> int = transform(value)
print(choose(on: 5, with: |value| value * 3))
fn dialog(confirm action: fn() -> int, title heading: str = "Ready") -> int =
action() + heading.len()
print(dialog(title: "Go") confirm { 7 })
fn double(value: int) -> int = value * 2
let labelled: fn(input: int) -> int = double
print(labelled(input: 9))
fn advance(from start: int, to finish: int = start + 2) -> int = finish - start
print(advance(from: 4))Cláusulas de función por patrón¶
Las declaraciones consecutivas de la misma función eligen el cuerpo por patrones de parámetros y guards opcionales, en el orden escrito. Forman una función y deben cubrir los casos; los guards solos no garantizan cobertura. Los contratos y etiquetas públicas deben coincidir.
Practica en By Example · Programa fuente
// Consecutive clauses form one function and try patterns in written order.
fn classify(0: int) -> str = "zero"
fn classify(n: int) if n > 0 -> str = "positive"
fn classify(n: int) -> str = "negative"
// Public argument labels are shared; binders remain local to each clause.
fn magnitude(value n: int) if n < 0 -> int = -n
fn magnitude(value n: int) -> int = n
print(classify(0))
print(classify(3))
print(classify(-3))
print(magnitude(value: -4))
// expected: zero
// expected: positive
// expected: negative
// expected: 4Lambdas unarias completas¶
Con una firma comprobada de callback de un argumento, underscore representa el parámetro completo, incluso en cálculos y llamadas anidadas comunes. Los callbacks anidados obtienen su propio parámetro. Bloques, lambdas explícitas, colecciones y pipes siguen siendo límites de alcance.
Practica en By Example · Programa fuente
// expected:
// 4
// 6
// Ana!
// 2
// 1
struct User { name: str }
fn format_name(name: str) -> str { name + "!" }
let doubled = [2, 3].map(_ * 2)
print(doubled[0])
print(doubled[1])
print([User { name: "Ana" }].map(format_name(_.name))[0])
// Each proved nested callback gets its own parameter.
let sizes = [[2, 3], [4]].map(_.map(_ + 1).len())
print(sizes[0])
print(sizes[1])Argumentos nombrados obligatorios¶
Los parámetros después de * deben pasarse con sus etiquetas externas. Los valores por defecto pueden omitirse. El contrato sigue métodos, declaraciones exportadas y valores de función tipados; pasar la función como callback no elimina el requisito.
Practica en By Example · Programa fuente
// Required names make call sites readable, including through a function value.
fn transfer(*,from:int,to:int,amount:int=1)->int=from-to+amount
let send=transfer
print(send(from:10,to:3,amount:2))
// Earlier parameters may remain positional; defaults still belong to the callee.
fn advance(start:int,*,by:int=1)->int=start+by
print(advance(7,by:2))Callbacks con match anónimo¶
La expresión match { patrón => valor, ... } crea una función de un argumento. El contexto del callback proporciona el tipo de entrada; los vínculos, las condiciones y la cobertura de casos siguen las reglas del match habitual.
// Pass a complete decision as a callback.
enum Reading { Waiting, Measured(int) }
fn show(reading: Reading, describe: fn(Reading) -> str) -> str {
describe(reading)
}
print(show(.Waiting, match {
.Waiting => "waiting",
.Measured(value) => "{value} units",
})) // expect: waiting
print(show(.Measured(12), match {
.Waiting => "waiting",
.Measured(value) => "{value} units",
})) // expect: 12 unitsAplicación parcial explícita¶
partial f(fijo, _) crea una función con un parámetro posicional por cada underscore, en el orden escrito. La función o el receptor y los argumentos fijos se evalúan una vez al crearla. Las etiquetas nombradas siguen perteneciendo a la función original.
// 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: 17Inicializadores de captura explícitos¶
capture { nombre: expresión } |parámetro| cuerpo evalúa los inicializadores una vez, de izquierda a derecha. Cada nombre pertenece a la closure creada. Las demás variables libres siguen las reglas habituales de captura.
// 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: 9Sigue aprendiendo¶
DOCS / OPINIÓN
¿Esta página dejó alguna pregunta?
Cuéntanos dónde te perdió la explicación. La documentación también forma parte de la experiencia del lenguaje.