Forwarded from мне не нравится реальность
В rust-analyzer changelog #114 есть и мой PR :')
rust-analyzer.github.io
Changelog #114
Commit: fd3942eRelease: 2022-01-31
🔥4🎉1
Forwarded from Протестировал (Sergey Bronnikov)
Крутейшая новость для тех, кто любит читать пейперы (а именно препринты на arXiv). Если в ссылке на abstract статьи заменить "arxiv" на "ar5iv", то можно читать статью в виде веб-страницы. Тут больше деталей - https://twitter.com/dginev/status/1488157927001268231
Примеры статей:
https://arxiv.org/html/1504.00204 → https://ar5iv.org/html/1504.00204
https://arxiv.org/html/2102.02527 → https://ar5iv.org/html/2102.02527
Примеры статей:
https://arxiv.org/html/1504.00204 → https://ar5iv.org/html/1504.00204
https://arxiv.org/html/2102.02527 → https://ar5iv.org/html/2102.02527
👍16
#prog #rust
Очень хороший пример применения паттерна typestate.
twitter.com/bloomofthehours/status/1488464978852163589
(thanks @ihatereality)
Очень хороший пример применения паттерна typestate.
twitter.com/bloomofthehours/status/1488464978852163589
(thanks @ihatereality)
Twitter
большой злой В.
как можно использовать систему типов в Rust, чтобы сделать удобный и безопасный API, проверяющий нужные инварианты на уровне компиляции 🧵
👍1
Forwarded from iggisv9t channel
Предлагаю запретить на paperswithcode считать код на матлабе за код.
👍3
#prog #rust
Хозяйке на заметку
Иногда требуется писать реализации трейтов вроде
Но мы можем написать код так, чтобы компилятор таки помогал! Первый способ — это сделать newtype, который будет в реализации
Разумеется, у этого метода есть и недостатки. Это довольно ad-hoc решение, это бойлерплейт (вы же хотите добавить реализациии очень длинное имя. Вдобавок, иногда нам требуется просто возможность для какой-то одной функции проигнорировать одно или два поля, но не забыть остальные с учётом тех, что могут добавить в будущем — в этом случае подход с newtype-ом может оказаться недостаточно гибким и в целом оверкиллом.
Для этих случаев годится другой способ. Мы можем воспользоваться тем фактом, что в let-биндинге может быть произвольный паттерн, который привязывает сразу несколько имён (а также тем фактом, что, начиная с версии 1.26, привязка ссылки к паттерну по значению привязывает суб-паттерны по ссылке) и явно показать, что какие-то поля мы игнорируем. Опять покажу на примере:
Хозяйке на заметку
Иногда требуется писать реализации трейтов вроде
PartialEq
и Hash
, для которых код не укладывается в прямолинейную схему derive-макросов. Например, в коде должны использоваться не непосредственно значения полей, а некоторая их комбинация, или же одно из полей должно быть проигнорировано при сравнении. Для того, чтобы разговор был более конкретным, покажем конкретный тип:struct Big {
field: u32,
another: Vec<u8>,
one_more: (i32, i32),
irrelevant: String,
}
Напишем для этого типа реализацию PartialEq
, которая будет игнорировать поле irrelevant
. Казалось бы, всё просто:impl PartialEq for Big {
fn eq(&self, rhs: &Self) -> bool {
self.field == rhs.field
&& self.another == rhs.another
&& self.one_more == rhs.one_more
}
}
Однако тут есть тонкий момент: если в структуру буду добавлены новые поля, то нужно будет не забыть дописать их сравнение в реализацию — и компилятор нам тут никак не поможет. Более того, исключения сравнения одного поля для программиста выглядит, как ошибка, и без поясняющего комментария следующий программист может "исправить" код и нарушить его логику.Но мы можем написать код так, чтобы компилятор таки помогал! Первый способ — это сделать newtype, который будет в реализации
PartialEq::eq
безусловно возвращать true
:struct UnconditionallyEqual<T>(T);
impl<T> PartialEq for UnconditionallyEqual<T> {
fn eq(&self, _other: &Self) -> bool {
true
}
}
В этом случае достаточно поменять тип поля irrelevant
на UnconditionallyEqual<String>
— и можно будет использовать стандартный #[derive(PartialEq)]
для достижения требуемого функционала. Бонусом мы получим очень хорошую передачу намерений, которая видна другим программистам.Разумеется, у этого метода есть и недостатки. Это довольно ad-hoc решение, это бойлерплейт (вы же хотите добавить реализации
Deref
и DerefMut
для удобства, верно?), это иной тип, что иногда может мешаться Для этих случаев годится другой способ. Мы можем воспользоваться тем фактом, что в let-биндинге может быть произвольный паттерн, который привязывает сразу несколько имён (а также тем фактом, что, начиная с версии 1.26, привязка ссылки к паттерну по значению привязывает суб-паттерны по ссылке) и явно показать, что какие-то поля мы игнорируем. Опять покажу на примере:
impl PartialEq for Big {
fn eq(&self, rhs: &Self) -> bool {
let Self { field, another, one_more, irrelevant: _ } = self;
*field == rhs.field
&& *another == rhs.another
&& *one_more == rhs.one_more
}
}
В этом случае код перестанет компилироваться, если мы добавим новые поля, так что возможность забыть их обработку исключена. Этот подход используется всюду в компиляторе самого Rust. Разумеется, это работает и с мутабельными ссылками.👍41