Zum Inhalt springen

Closures

Welche der folgenden Aussagen beschreibt am besten die Begründung, warum Rust die Typen von Argumenten/Rückgabewerten für Closures, aber nicht für Top-Level-Funktionen inferiert?

Rust könnte theoretisch Typinferenz für Top-Level-Funktionen bereitstellen. Funktionale Sprachen wie Haskell und OCaml verfügen über diese Funktion. Die Rust-Designer haben jedoch bewusst entschieden, Typannotationen für Top-Level-Funktionen zu verlangen, um die Klarheit auf der Schnittstellenebene zu fördern: Eine Funktion wird immer genau den Typ haben, den sie angibt.


Rust erlaubt Pattern Matching innerhalb von Closure-Argumenten, einschließlich der Verwendung des Unterstrichs. Zum Beispiel könnten Sie Folgendes schreiben:

let f = |_| (); // manchmal als "Toilet Closure" bezeichnet
let s = String::from("Hello");
f(s);

Welche der folgenden Aussagen beschreibt am besten die Beziehung zwischen f und s in diesem Programm?

Die „Toilet Closure“ ähnelt std::mem::drop, d.h. einer Funktion, die ein Argument verschiebt und bewirkt, dass es fallen gelassen wird (dropped).


fn main() {
let mut s = String::from("Hello");
let mut add_suffix = || s.push_str(" world");
println!("{s}");
add_suffix();
}

add_suffix leiht s zwischen seiner Definition und Verwendung mutabel aus, daher ist der println-Aufruf (ein Lesezugriff auf s) ungültig.


fn main() {
let mut s = String::from("Hello");
let add_suffix = |s: &mut String| s.push_str(" world");
println!("{s}");
add_suffix(&mut s);
}

Da add_suffix s nicht erfasst, ist es in Ordnung, s zu lesen, bevor es mit add_suffix mutiert wird.


Betrachten Sie die folgende API:

/// Executes a function with a mutable reference to each element of a vector
fn for_each_mut<T, F: ___(&mut T)>(v: &mut Vec<T>, mut f: F) {
for x in v.iter_mut() {
f(x);
}
}

Welcher der folgenden Funktionstraits ist am besten geeignet, um die Lücke zu füllen?

f wird mehrfach aufgerufen, daher ist FnOnce nicht geeignet. Sowohl Fn als auch FnMut können funktionieren, und FnMut ist weniger restriktiv, daher ist FnMut am besten geeignet.


Betrachten Sie die folgende API:

pub struct Analyzer<F> {
postprocess: F
}
impl<F: ___(i32) -> i32> Analyzer<F> {
fn process(&self, n: i32) -> i32 { /* .. */ }
pub fn pipeline(&self, n: i32) -> i32 {
let n = self.process(n);
(self.postprocess)(n)
}
}

Welcher der folgenden Funktionstraits ist am besten geeignet, um die Lücke zu füllen?

pipeline könnte mehrfach aufgerufen werden, daher ist FnOnce nicht geeignet. pipeline nimmt eine unveränderliche Referenz auf self. Wäre postprocess vom Typ FnMut, könnte es nicht innerhalb von pipeline aufgerufen werden. Daher ist Fn hier am besten geeignet.