Pular para o conteúdo

Guia 12 de 53

Parâmetros de funções e lambdas

Lambdas, rótulos, blocos de callback e cláusulas por padrão.

Nesta página

Lambdas, rótulos, blocos de callback e cláusulas por padrão.

Lambdas curtas de predicado

Acessos iniciados por underscore usam o mesmo parâmetro implícito. Combine campos, contas e testes booleanos no callback; use uma lambda explícita quando o escopo ficar ambíguo.

Pratique na By Example · Programa fonte

// 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 nomeados abreviados

Uma chamada com name: passa a variável name do chamador. Valores explícitos e abreviados podem ser misturados e reordenados pelo rótulo. Uma variável ausente é um erro; o formatador preserva a abreviação.

Pratique na By Example · Programa fonte

// 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>
}

Funções com corpo de expressão

Use = expressão em uma função ou método pequeno. A expressão fornece o retorno, enquanto return, propagação de Result, generics e defaults preservam a mesma semântica de um corpo em bloco.

Pratique na By Example · Programa fonte

// 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

Blocos finais nomeados

Vários callbacks podem aparecer depois da chamada como blocos com rótulos. Os rótulos resolvem os parâmetros de função, permitindo outra ordem. Criar o callback não executa seu corpo; capturas mutáveis preservam suas células.

Pratique na By Example · Programa fonte

// 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

Rótulos externos de argumentos

Separe o rótulo público do nome local do parâmetro: from source: int. O chamador usa from:, enquanto a função lê source. Rótulos fazem parte da interface e continuam disponíveis em valores de função.

Pratique na By Example · Programa fonte

// 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 função por padrão

Declarações consecutivas da mesma função escolhem o corpo pelos padrões dos parâmetros e guards opcionais, na ordem escrita. As cláusulas formam uma função e precisam cobrir os casos; guards sozinhos não garantem cobertura. Contratos e rótulos públicos precisam coincidir.

Pratique na By Example · Programa fonte

// 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 unárias completas

Com uma assinatura comprovada de callback de um argumento, underscore pode representar o parâmetro inteiro, inclusive em contas e chamadas aninhadas comuns. Callbacks aninhados ganham seu próprio parâmetro. Blocos, lambdas explícitas, coleções e pipes continuam sendo fronteiras de escopo.

Pratique na By Example · Programa fonte

// 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 nomeados obrigatórios

Parâmetros depois de * precisam ser passados com seus rótulos externos. Defaults ainda podem ser omitidos. O contrato acompanha métodos, declarações exportadas e valores de função tipados; passar a função como callback não remove a exigência.

Pratique na By Example · Programa fonte

// 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 com match anônimo

A expressão match { padrão => valor, ... } cria uma função de um argumento. O contexto do callback fornece o tipo de entrada; vínculos, condições e cobertura dos casos seguem as regras do match comum.

// 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

Aplicação parcial explícita

partial f(fixo, _) cria uma função com um parâmetro posicional para cada underscore, na ordem escrita. A função ou o receptor e os argumentos fixos são avaliados uma vez na criação. Os rótulos nomeados continuam pertencendo à função 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 { nome: expressão } |parâmetro| corpo avalia os inicializadores uma vez, da esquerda para a direita. Cada nome pertence à closure criada. As demais variáveis livres seguem as regras usuais 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

Continue aprendendo

Documentação · Pratique na By Example

DOCS / OPINIÃO

Esta página deixou alguma pergunta?

Conte onde a explicação perdeu você. A documentação também faz parte da experiência da linguagem.

Índice global

Encontre seu caminho pela Zolo

Experimente uma ideia

Comece por aqui

9 resultados

9 resultados

enespt-br