Réflexions sur la rouille

Bonjour. Pas tout de suite, mais j'ai adoré Rust. Et cet amour m'a conduit vers les mers interminables du code sans loi. À propos de ce que j'ai réussi à trouver - sous la coupe.





Type de données secret

Si vous avez lu le Rust Book, vous vous souvenez probablement d'un extrait de code similaire:





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));
}
      
      



Vérifier





Bien sûr, il n'y a rien d'inhabituel ici. Renvoyez la valeur dans Option, s'il y en a une, ou appelez la fin du processus à l'aide de la macro panic !. Mais vous êtes-vous déjà demandé pourquoi ce code se compile ? Comment le compilateur sait-il qu'une fonction qui retourne T peut renvoyer ... ceci?





, - 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);
        })
    ];
      
      



, , , ? . , . , .





La rouille, aussi bonne soit-elle, peut parfois susciter la réflexion. Pourquoi ne conserve-t-il pas la capacité de changement? Pourquoi le calcul fonctionnel a-t-il été rendu paresseux? Pourquoi cargo crée-t-il des dossiers étranges avec des hachages pour chaque occasion, au lieu de créer les mêmes bibliothèques une fois (bien que, pour être honnête, ce ne soit pas un problème de langage lui-même)? Quoi qu'il en soit, si écrire sur les avantages consiste à se tirer une balle dans le pied, alors écrire sur un rast revient à essayer de se tirer une balle dans le pied (et Dieu vous interdit d'utiliser ffi dans le projet, alors les tentatives peuvent être assez fructueuses) .





Le but de cet article est d'essayer d'approfondir la langue, de comprendre son fonctionnement de l'intérieur, car, comme vous le savez, vous ne pouvez aimer que quelqu'un que vous comprenez.








All Articles