Rust vs. Zustand

Wichtig : Um den Artikel bequem lesen zu können, müssen Sie in der Lage sein, den Quellcode in Rust zu lesen und zu verstehen, warum Rc<RefCell<...>>es schlecht ist, alles einzupacken.



Einführung



Rust wird im Allgemeinen nicht als objektorientierte Sprache betrachtet: Es gibt keine Implementierungsvererbung. auf den ersten Blick gibt es auch keine Einkapselung; Schließlich sehen die Abhängigkeitsgraphen von veränderlichen Objekten, die OOP-Adepten so vertraut sind, so hässlich wie möglich aus (sehen Sie sich nur all diese Rc<RefCell<...>>und Arc<Mutex<...>>!) An.



Zwar wird die Vererbung von Implementierungen seit mehreren Jahren als schädlich angesehen, und OOP-Gurus sagen sehr korrekte Dinge wie "Ein gutes Objekt ist ein unveränderliches Objekt". Also fragte ich mich: Wie gut passen Object Thinking und Rust wirklich zusammen ?



Das erste Meerschweinchen wird das Staatsmuster sein, dessen reine Umsetzung Gegenstand dieses Artikels ist.



Es wurde aus einem Grund ausgewählt: Ein Kapitel aus The Rust Book widmet sich demselben Muster . Das Ziel dieses Kapitels war es zu zeigen, dass nur böse Jungen und Mädchen objektorientierten Code in Rust schreiben: Hier müssen Sie sowohl unnötige Optionals auch triviale Methodenimplementierungen kopieren und in alle Implementierungen des Merkmals einfügen. Wenn Sie jedoch ein paar Tricks anwenden, verschwindet die gesamte Boilerplate und die Lesbarkeit wird verbessert.



Arbeitsumfang



workflow . :



  1. - , .
  2. , .
  3. , .
  4. , .


(, ).



, .



// main.rs

use article::Article;

mod article;

fn main() {
    let mut article = Article::empty();

    article.add_text("Rust    -");
    assert_eq!(None, article.content());

    article.send_to_moderators();
    assert_eq!(None, article.content());

    article.publish();
    assert_eq!(Some("Rust    -"), article.content());
}


Article :



// article/mod.rs

pub struct Article;

impl Article {
    pub fn empty() -> Self {
        Self
    }

    pub fn add_text(&self, _text: &str) {
        // no-op
    }

    pub fn content(&self) -> Option<&str> {
        None
    }

    pub fn send_to_moderators(&self) {
        // no-op
    }

    pub fn publish(&self) {
        // no-op
    }
}


, . !





State, Draft Article:



// article/state.rs

pub trait State {
    // empty
}

// article/states.rs

use super::state::State;

pub struct Draft;

impl State for Draft {
    // nothing
}

// article/mod.rs

use state::State;
use states::Draft;

mod state;
mod states;

pub struct Article {
    state: Box<dyn State>,
    content: String,
}

impl Article {
    pub fn empty() -> Self {
        Self {
            state: Box::new(Draft),
            content: String::new(),
        }
    }

    // ...
}




State, . , - :



trait State {
    fn send_to_moderators(&mut self) -> &dyn State;
}


, , , — .



?



pub trait State {
    fn send_to_moderators(&mut self) -> Box<dyn State>;
}


. . , ?



:



pub trait State {
    fn send_to_moderators(self: Box<Self>) -> Box<dyn State>;
}


: ( self). , Self: Sized, .. . trait object, .. .





: , , , . , , ; , .



P.S.: Amethyst.



use crate::article::Article;

pub trait State {
    fn send_to_moderators(&mut self) -> Transit {
        Transit(None)
    }
}

pub struct Transit(pub Option<Box<dyn State>>);

impl Transit {
    pub fn to(state: impl State + 'static) -> Self {
        Self(Some(Box::new(state)))
    }

    pub fn apply(self, article: &mut Article) -> Option<()> {
        article.state = self.0?;
        Some(())
    }
}


, , Draft:



// article/states.rs

use super::state::{State, Transit};

pub struct Draft;

impl State for Draft {
    fn send_to_moderators(&mut self) -> Transit {
        Transit::to(PendingReview)
    }
}

pub struct PendingReview;

impl State for PendingReview {
    // nothing
}

// article/mod.rs

impl Article {
    // ...
    pub fn send_to_moderators(&mut self) {
        self.state.send_to_moderators().apply(self);
    }
    // ...
}


-



: Published, State, publish PendingReview. Article::publish :)



. content State, Published , , Article:



// article/mod.rs

impl Article {
    // ...
    pub fn content(&self) -> Option<&str> {
        self.state.content(self)
    }
    // ...
}

// article/state.rs

pub trait State {
    // ...
    fn content<'a>(&self, _article: &'a Article) -> Option<&'a str> {
        None
    }
}

// article/states.rs

impl State for Published {
    fn content<'a>(&self, article: &'a Article) -> Option<&'a str> {
        Some(&article.content)
    }
}


, ? , !



impl Article {
    // ...
    pub fn add_text(&mut self, text: &str) {
        self.content.push_str(text);
    }
    // ...
}


( ) , .



! !



, Article , - , , . ? , ! .





.



, - Rust , , . - -.



, , Rust . , Observer: , Arc<Mutex<...>>!



, .




All Articles