Saltar al contenido

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 required

Bloques 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: 1

Etiquetas 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: 4

Lambdas 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 units

Aplicació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: 17

Inicializadores 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: 9

Sigue aprendiendo

Documentación · Practica en By Example

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.

Índice global

Encuentra tu camino por Zolo

Prueba una idea

Empieza aquí

9 resultados

9 resultados

enespt-br