Reflexionen über Rost

Hallo. Nicht sofort, aber ich habe Rust geliebt. Und diese Liebe führte mich zu den endlosen Meeren des gesetzlosen Kodex. Über das, was ich gefunden habe - unter dem Schnitt.





Geheimer Datentyp

Wenn Sie das Rostbuch gelesen haben, erinnern Sie sich wahrscheinlich an einen ähnlichen Snippet-Code:





fn unwrap<T>(option: Option<T>) -> T{
    let unwrapped = match option{
        Some(val) => val,
        None => panic!("This cannot be None!")
    };
    return unwrapped;
}

fn main() {
    let unwrapped = unwrap(Some(0));
}
      
      



Überprüfen





Natürlich gibt es hier nichts Ungewöhnliches. Geben Sie den Wert in Option zurück, falls vorhanden, oder rufen Sie die Prozessbeendigung mit dem Panic! -Makro auf. Aber haben Sie sich jemals gefragt, warum dieser Code kompiliert wird ? Woher weiß der Compiler, dass eine Funktion, die T zurückgibt, ... dies zurückgeben kann?





, - panic "!".





"!" . ? :





#![feature(never_type)]
use std::convert::TryInto;

#[derive(Debug)]
enum ConnectionError{
    BrokenPipe,
    BadId,
    Other
}

struct Client;
struct Request;
struct Response;

impl Request{
    pub fn build_response(&self) -> Response{
        Response
    }
}

fn get_request(id: i32) -> Result<(Client, Request), ConnectionError>{
    match id % 2 == 0{
        true => {
            Ok((Client, Request))
        },
        false => {
            Err(ConnectionError::BadId)
        }
    }
}

fn init_server() -> Result<!, ConnectionError>{
    loop {
        let (client, request) = get_request(5i32)?;
        let resp = request.build_response();
    };
}

fn main() {
    let x: ! = init_server().unwrap();
}
      
      







, , nightly , "!" "()":





fn init_server() -> Result<(), ConnectionError>{
    loop {
        let (client, request) = get_request(5i32)?;
        let resp = request.build_response();
    };
}

fn main() {
    let x = init_server().unwrap();
}
      
      



? , :





fn main() {
    match init_server(){
        Ok(v) => { println!("unreachable? {:?}", v); },
        Err(_) => {}
    }; 
}
      
      



, Ok(v) - . , , . , , , .





? , v



"". "!" , break



, continue



std::process::exit



.





, , . #![feature(never_type)]



? , , , . , , . panic, expect, todo unimplemented. "!"?





, . , .





Rust ( - , ) Fn



. - - ("closures" "", ), , . ?





, , , impl Trait. , , ...





use std::any::type_name;
fn type_of<T>(x: T) -> &'static str {
    type_name::<T>()
}

fn callback() -> impl Fn(f32) -> f32{
    |a| {
      a*2.  
    }
}

fn main() {
    let x = callback();
    println!("{}", type_of(x));
}
      
      



: playground::callback::{{closure}}



. , , impl Fn(f32) -> f32



, , . , trait object, dyn. - , trait object, Box:





fn main() {
    let x: Box<dyn Fn(f32) -> f32> = Box::new(callback());
    println!("{}", type_of(x));
}
      
      



:





alloc::boxed::Box&lt;dyn core::ops::function::Fn&lt;(f32,)>+Output = f32>







: , , .





, :





use tokio; // 1.0.2
use tokio::task::JoinError;
use futures::prelude::*; // 0.3.12

async fn job1(){}

async fn job2(){
	for i in 0..5{}
}

async fn job() -> Vec<impl Future<Output = Result<(), JoinError>>>{
    vec![
    tokio::spawn(async move{
        job1().await;
    }),
    tokio::spawn(async move{
        job2().await;
    })]
}

#[tokio::main]
async fn main() {
    let mut v = job();
}
      
      



, - tokio::spawn



tokio::task::JoinHandle



. , JoinHandle - , , async{}



, , async-, ?





let v = vec![
        Box::new(async{}),
        Box::new(async{
            let cb = |x| x*2.;
            let val = cb(1f32);
        })
    ];
      
      



, , , ? . , . , .





Rost, so gut er auch ist, kann manchmal zum Nachdenken anregen. Warum bleibt die Änderungskapazität nicht erhalten? Warum wurde die Funktionsrechnung faul gemacht? Warum erstellt Fracht für jeden Anlass seltsame Ordner mit Hashes, anstatt dieselben Bibliotheken einmal zu erstellen (obwohl dies fairerweise kein Problem der Sprache selbst ist)? Wie auch immer, wenn das Schreiben auf Pluspunkten bedeutet, sich in den Fuß zu schießen, dann bedeutet das Schreiben auf einem Rast, zu versuchen, sich in den Fuß zu schießen (und Gott bewahre, dass Sie ffi im Projekt verwenden, dann können Versuche recht erfolgreich sein). .





Der Zweck dieses Artikels ist es, tief in die Sprache einzutauchen und zu verstehen, wie sie von innen funktioniert, denn wie Sie wissen, können Sie nur jemanden lieben, den Sie verstehen.








All Articles