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 requiredBlocos 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: 1Ró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: 4Lambdas 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 unitsAplicaçã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: 17Inicializadores 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: 9Continue aprendendo¶
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.