Funktionen, Closures & Lambdas
Funktionen sind "First-Class Citizens" in Velisch - sie können Variablen zugewiesen und als Argumente übergeben werden.
Normale Funktionen
// Standard-Funktion
fn add(a: number, b: number): number {
return a + b;
}
// Kurzform für einzeilige Rückgaben (implizit return)
fn multiply(a: number, b: number) => a * b;
// Funktion ohne Rückgabewert
fn printMessage(msg: string): void {
log.info(msg);
}
// Async Funktion
async fn fetchData(url: string): Data {
let response = await http.get(url);
return response.json();
}Optionale Parameter & Default-Werte
fn greet(name: string, greeting: string = "Hallo") {
log.info(greeting + ", " + name + "!");
}
greet("Max"); // "Hallo, Max!"
greet("Lisa", "Moin"); // "Moin, Lisa!"
// Mit mehreren optionalen Parametern
fn createUser(
name: string,
role: string = "user",
active: boolean = true
): User {
return User { name, role, active };
}Lambdas (Anonyme Funktionen)
Lambdas sind besonders kompakt und nützlich für Callbacks. Syntax: |param1, param2| expression
let numbers = [1, 2, 3];
// Lambda als Argument
let doubled = numbers.map(|n| n * 2);
// Lambda mit Block
let processed = numbers.map(|n| {
let squared = n * n;
return squared + 1;
});
// Lambda in Variable speichern
let doubler = |n| n * 2;
log.info(doubler(5)); // 10
// Lambda mit expliziten Typen
let add: fn(number, number) -> number = |a, b| a + b;Closures
Closures sind Lambdas, die Variablen aus ihrem definierenden Scope "fangen" (capture). Dies ist extrem mächtig für Konfigurationen, Event-Handler oder funktionale Komposition.
fn createAdder(base: number): fn(number) -> number {
// Die zurückgegebene Funktion "merkt" sich 'base'
return |n| n + base;
}
let addFive = createAdder(5);
let addTen = createAdder(10);
log.info(addFive(2)); // 7
log.info(addTen(2)); // 12
// Closure mit mehreren gefangenen Variablen
fn createMultiplier(factor: number, offset: number): fn(number) -> number {
return |n| (n * factor) + offset;
}
let transform = createMultiplier(2, 10);
log.info(transform(5)); // 20Praktische Anwendungen
Event Handler
fn setupButton(buttonId: string, action: fn() -> void) {
ui.onClick(buttonId, action);
}
let counter = 0;
setupButton("increment", || {
counter = counter + 1;
ui.update("count", counter);
});Konfigurierbare Filter
fn createAgeFilter(minAge: number): fn(User) -> boolean {
return |user| user.age >= minAge;
}
let adults = createAgeFilter(18);
let seniors = createAgeFilter(65);
let allUsers = db.findAll(User);
let adultUsers = allUsers.filter(adults);
let seniorUsers = allUsers.filter(seniors);Middleware-Pattern
fn withLogging<T>(operation: fn() -> T): fn() -> T {
return || {
log.info("Operation started");
let result = operation();
log.info("Operation completed");
return result;
};
}
let fetchWithLogging = withLogging(|| {
return http.get("https://api.example.com/data");
});Performance
Stack-Allokation
Lokale Closures werden auf dem Stack alloziert
Inlining
Kleine Closures werden oft vom Compiler geinlined
Zero-Cost
Closures haben keine Laufzeit-Overhead gegenüber normalen Funktionen
Move Semantics
Captured Values werden effizient nach Rust übersetzt
Best Practices
Kleine Closures
Halte Closures kurz und fokussiert
Klare Namen
Benenne Closure-Variablen beschreibend
Capture minimieren
Fange nur Variablen, die du wirklich brauchst
Typen dokumentieren
Bei komplexen Closures explizite Typen angeben