увидел довольно оригинальную технику реализации паттерна State на расте. На других языках такое городить тоже можно, но результат может не воодушевить.
Допустим реализуем сетевое соединение. Оно может быть либо в закрытом состоянии, либо открытом. Нам желательно в compile time запретить вызов метода close или write для ещё не открытого соединения (в классической реализации бросали исключения).
Приступим к реализации.
Сначала делаем пустые структуры для маркера состояния:
struct Open;
struct Close;
Затем реализуем собственно класс соединения:
struct Connection<State = Close> {
...
state: std::marker::PhantomData<State>, // иначе получим ошибку error[E0392]: parameter `State` is never used
}
Реализуем наши методы для закрытого соединения:
impl Connection<Close> {
fn open(self) -> Connection<Open> { todo!(); }
}
И для открытого:
impl Connection<Open> {
fn close(self) -> Connection<Close> { todo!(); }
fn write(&self, _data: &[u8]) { todo!(); }
}
Пишем конструктор:
impl Connection {
fn new() -> Connection {
Connection{ state: std::marker::PhantomData }
}
}
Теперь всё готово для использования
fn main() {
let con = Connection::new().open();
con.write("Hello".to_owned().as_bytes());
let con = con.close();
}
Об остальном позаботится компилятор. Вызвать два раза open или close невозможно (на том же C++ это запретить тяжело). Попытаться записать что-то в закрытое соединение не получится.
Остаются только философские вопросы использования. Н-р соединение может стать закрытым не по нашей воле. Или как вообще хранить объект соединение? Получается только в открытом состоянии (в закрытом возможно смысла не имеет).
То есть вопросы по сравнению с классической реализацией конечно есть, но и выгода тоже наличиствует. Лично я классически паттерн state реализовывал только однажды. После получившегося "переусложнизма" зарёкся когда-либо ещё писать подобные конструкции. Такую же технику попробовать можно. Тут дублирование минимально.
Код
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=49b593914d0a35583e64860a1b8f17e6
Оригинал на английском (и более подробно) можно послушать здесь
https://www.youtube.com/watch?v=_ccDqRTx-JU