Listings Breitbart/Lankes Rust, Teil 2

Listing 1: Generische Typen
struct Vektor<T> {
    x: T,
    y: T,
    z: T,
}

fn richtung<T: std::ops::Sub<Output = T>>(start: Vektor<T>, ziel: Vektor<T>) -> Vektor<T> {
    Vektor {
      x: ziel.x - start.x,
      y: ziel.y - start.y,
      z: ziel.z - start.z,
    }
}

-----

Listing 2: Beispiel für die Fehlerbehandlung
enum MathError {
    DivisionByZero,
    NonPositiveLogarithm,
    NegativeSquareRoot,
}

fn sqrt(x: f64) -> Result<f64, MathError> {
     if x < 0.0 {
      Err(MathError::NegativeSquareRoot)
    } else {
      Ok(x.sqrt())
    }
}

-----

Listing 3: Rückgabewert auswerten
match sqrt(42).0) { {
    Err(why) => panic!("math error"),
    Ok(result) => println!("result {}", result);
}

let result = sqrt(24.0, 0.0).unwrap();
println!("result {}", result);

-----

Listing 4: Verwendung optionaler Rückgabewerte
fn find(kundennummer: u64) -> Option<String> {
    ...
}

match find(123456) {
    Some(i) => println!("Kunde {} gefunden", i),
    None => println!("Kunde nicht gefunden"),
}

-----

Listing 5: Beispiel für Iteratoren
let mut v1 = std::vec::Vec::<i32>::new();
let mut v2 = std::vec::Vec::<i32>::new();

v1.push(1);
v2.push(2);
v1.push(-3);
v2.push(4);
v1.push(5);
v2.push(6);

let sum: i32 = v1
    .iter() // Iterator von v1 erstellen
    .zip(v2.iter()) // den Iterator von v1 mit einem von v2 verknüpfen
    .filter(|(a,b)| a.is_positive()) // nur die Elemente benutzen, bei denen der Eintrag von v1 positiv ist
    .map(|(a, b)| a * b) // eine Operation auf den verbleibenden Elementen ausführen
    .sum(); // die Ergebnisse summieren
assert!(sum == 1*2+5*6);

-----

Listing 6: Variablenzugriff über einen Mutex schützen
static readonly_number: u64 = 42;
static counter: Mutex<u64> = Mutex::new(0);

pub fn init() {
    let guard = counter.lock().unwrap();
    guard = readonly_number;
}

-----

Listing 7: Die Zahl π mithilfe von Rayon berechnen
let step = 1.0 / NUM_STEPS as f64;

let sum: f64 = (0..NUM_STEPS).into_par_iter()
    .map(|i| {
        let x = (i as f64 + 0.5) * step;
        4.0 / (1.0 + x * x)
    }).sum();

-----

Listing 8: Das Gerüst für Hello World erstellen
[package]
name = "hello_world"
version ="0.1.0"
authors = ["ix <ix@heise.de>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

-----

Listing 9: Beispiel für das Veröffentlichen von Funktionen
// Deklarieren einer privaten Struktur
struct Foo;

// Deklarieren einer öffentlichen Struktur mit privaten Elementen
pub struct Bar {
    field: i32,
}

// Privates Modul, das nicht außerhalb des Crates erreichbar ist
mod crate_helper_module {

    // Diese Funktion lässt sich innerhalb des kompletten Crates verwenden
    pub fn crate_helper() {}

    // Diese Funktion ist nur innerhalb des Moduls sichtbar
    fn implementation_detail() {}
}

// Modul, das auch außerhalb des Crates sichtbar ist
pub mod submodule {
    use crate_helper_module;

    // Öffentliche Funktion, die eine nur innerhalb des Crates
    // sichtbare Funktion exportiert
    pub fn my_method() {
      crate_helper_module::crate_helper();
    }
}

-----

Listing 10: HTTP-Anfragen mit der POST-Methode
#[derive(FromForm)]
struct UserLogin<'r> {
    username: &'r RawStr,
    password: &'r RawStr,
}

#[post("/login", data = "<user_form>")]
fn login(user_form: Form<UserLogin>) -> String {
    format!("Hello {}! You use password {}!", user_form.username, user_form.password)
}

-----

Listing 11: Daten mit der POST-Methode hochladen
#[post("/upload", format = "plain", data = "<data>")]
fn upload(data: Data) -> Result<String, Debug<io::Error>> {
    data.stream_to_file(env::temp_dir().join("upload.txt"))
        .map(|n| n.to_string())
        .map_err(Debug)
}
