Forwarded from USSResearch
Eli Albert Loeb из Калифорнии написал или написала любопытную бакалаварскую работу (чтобы все бакалавры в России писали такие работы) про маскулиность гопников и истоки этого явления.
Почитать можно совершенно бесплатно
Почитать можно совершенно бесплатно
Блог*
Редкие эпизоды из абсурдной жизни программиста. "Две пиццы — это не про размер команды, а про размер фонда оплаты труда" @topizza #blogrecommendation
К сожалению, больше не могу рекомендовать. Мало то, что контент пошёл куда-то не туда, так ещё и в последние пару дней там начался откровенный скам.
Forwarded from Life of Tau
Статья о том, зачем на самом деле штуки типа mod.rs, index.html и так далее и как от них избавиться
#prog #article #fs
#prog #article #fs
Felix’s Blog
The Tree Structure of File Systems
I’ve been using file system for a long time and have always thought of them as tree data structures. A couple of days ago, I had a realization that seems obvious in retrospect, but didn’t occur to me all those years before: The file system tree is different…
Блог*
#prog #rust #моё Допустим, нам нужно проанализировать большой JSON, и нам нужно вытащить часть полей с конкретными типами, но по возможности оставить остальные. При этом этот наборы полей в разных местах немного разные, так что повторять себя не хочется.…
#prog #rust #моё
При отладке подобного кода — с гетерогенными списками — может быть полезным иметь возможность их распечатывать. Казалось бы, фигня вопрос: просто навесим
При отладке подобного кода — с гетерогенными списками — может быть полезным иметь возможность их распечатывать. Казалось бы, фигня вопрос: просто навесим
#[derive(Debug)] — и дело с концом:#[derive(Debug)]
struct HNil;
#[derive(Debug)]
struct HCons<H, T> {
head: H,
tail: T,
}
Но всё не так радужно. Попробуем распечатать hlist![42, 'b', "sup", ((), (3.4, Vec::<i32>::new()))]:HCons { head: 42, tail: HCons { head: 'b', tail: HCons { head: "sup", tail: HCons { head: ((), (3.4, [])), tail: HNil } } } }
Ну... Выглядит не особо читаемо. Но ведь если использовать "{:#?}" в качестве форматной строки, станет лучше, ведь так?HCons {
head: 42,
tail: HCons {
head: 'b',
tail: HCons {
head: "sup",
tail: HCons {
head: (
(),
(
3.4,
[],
),
),
tail: HNil,
},
},
},
}
Нет, не стало. Мало того, что детали реализации просачиваются в вывод и замусоривают его, так ещё и добавляется по уровню вложенности на каждый элемент логически плоской последовательности. Вывод однозначен: нужно писать реализацию Debug руками.Но как именно это сделать? Первый способ, лежащий на поверхности (aka способ ленивого программиста) — собрать в массив вектор элементы гетерогенного списка, ослабленные до
Так как
dyn Debug, и попросту отформатировать этот вектор.Так как
HNil и HCons — разные типы, нам нужно абстрагировать в трейт общую для них операцию, а именно — добавление элементов в переданный вектор. Как должна выглядеть сигнатура метода? Кажется, что как-то так:fn append_fmt_items(&self, items: &mut Vec<&dyn Debug>)
...но это так не работает. Дело в том, что сигнатура говорит о том, что времена жизни ссылки на self и ссылок на трейт-объекты не связаны друг с другом. Но это явно не так, ведь мы собираемся класть в items данные из self! Что ж, выразим этот факт в коде:trait AppendFmt {
fn append_fmt_items<'a>(&'a self, items: &mut Vec<&'a dyn Debug>);
}
Теперь напишем реализации для компонент списка:impl AppendFmt for HNil {
fn append_fmt_items<'a>(&'a self, _: &mut Vec<&'a dyn Debug>) {
/* nothing to do here */
}
}
impl<H, T> AppendFmt for HCons<H, T>
where
H: Debug,
T: AppendFmt,
{
fn append_fmt_items<'a>(&'a self, items: &mut Vec<&'a dyn Debug>) {
items.push(&self.head);
self.tail.append_fmt_items(items);
}
}
Теперь мне бы очень хотелось написать impl<T: AppendFmt> Debug for T... но, к сожалению, мне не даст компилятор, потому что это будет перекрываться с impl<T: Debug> Debug for &'_ T. Так что, стиснув зубы, пишем руками:impl Debug for HNil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let list: &[&dyn Debug] = &[];
list.fmt(f)
// или просто f.write_str("[]")
}
}
impl<H, T> Debug for HCons<H, T>
where
Self: AppendFmt,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut items = Vec::new();
self.append_fmt_items(&mut items);
items.fmt(f)
}
}
Проверив, снова распечатав hlist![42, 'b', "sup", ((), (3.4, Vec::<i32>::new()))]:[42, 'b', "sup", ((), (3.4, []))]
А если попросить "красивую" печать?[
42,
'b',
"sup",
(
(),
(
3.4,
[],
),
),
]
Гораздо лучше.doc.rust-lang.org
Debug in std::fmt - Rust
`?` formatting.
Но действительно ли нам нужно собирать всё в один вектор и лишний раз выделять память? Мы же можем поступить так же, как и реализация Debug для слайса: воспользоваться хелпером std::fmt::DebugList и скормить ему элементы списка. Единственной сложностью тут выступает то, что мы, очевидно, не можем (ну то есть можем, но не хотим, потому что это потребует написания дофига кода и будет неэффективно в рантайме) воспользоваться DebugList::entries, так что придётся скармливать элементы по одному при помощи DebugList::entry.
Снова выделим общий функционал в отдельный трейт:
P. S.: как всегда, весь код в гисте.
Снова выделим общий функционал в отдельный трейт:
trait HlistFmt {
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result;
}
Реализуем для HNil и HCons:impl HlistFmt for HNil {
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result {
list.finish()
}
}
impl<H, T> HlistFmt for HCons<H, T>
where
H: Debug,
T: HlistFmt,
{
fn finish_fmt(&self, list: &mut DebugList<'_, '_>) -> fmt::Result {
list.entry(&self.head);
self.tail.finish_fmt(list)
}
}
Теперь через это реализуем Debug:impl Debug for HNil {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.finish_fmt(&mut f.debug_list())
// или опять f.write_str("[]")
}
}
impl<H, T> Debug for HCons<H, T>
where
Self: HlistFmt,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.finish_fmt(&mut f.debug_list())
}
}
Если мы теперь распечатаем тот же самый пробный список, то мы получим те же самые результаты, так что показывать это я не буду.DebugList — не единственный хелпер для форматирования в std, есть также DebugMap, DebugSet, DebugStruct и DebugTuple, суть функционала которых ясна из названий. Эти вещи сильно облегчают написание кастомных реализаций Debug, так что используйте их, пожалуйста.P. S.: как всегда, весь код в гисте.
doc.rust-lang.org
slice - Rust
A dynamically-sized view into a contiguous sequence, `[T]`.
За час с момента публикации пост расшарили трижды, но ни одного комментария не последовало. Всё и так понятно или всё совсем непонятно? 🤔
Forwarded from Санечка Ъысь (Anna Weiss)
This media is not supported in your browser
VIEW IN TELEGRAM
Forwarded from мне не нравится реальность
Наткнулся в твиттере на анонс интересного инструмента:
> cargo-hakari
Он автоматизирует создание и поддержку "workspace-hack" крейтов, ускоряя компиляцию для больших воркспейсов. Что такое "workspace-hack" и зачем его используют в rustc и firefox — читайте в треде.
> cargo-hakari
Он автоматизирует создание и поддержку "workspace-hack" крейтов, ускоряя компиляцию для больших воркспейсов. Что такое "workspace-hack" и зачем его используют в rustc и firefox — читайте в треде.
Twitter
rain 🌧
Announcing cargo-hakari, an easy-to-use way to generate and manage Cargo workspace-hack packages. Speed up your local @rustlang builds by up to 95%, and cumulatively by 25% or more! 🧵follows. crates.io/crates/cargo-h…
Forwarded from Врен о Японии для туриста
Вы не поверите, но это японские блины. Их подают в Crepes de Anne в Нагое.
#prog #rust #rustlib #serde
Трейт Deserializer имеет методы вида deserialize_type. Трейт Serializer имеет методы вида serialize_type. Что это значит? Это значит, что одно можно непосредственно сцепить с другим, и таким образом перегонять данные из одного формата данных, поддерживаемых serde, в другой, никогда не материализуя экземпляры соответствующих типов в памяти целиком. Собственно, именно это и делает serde-transcode.
Пример из документации (преттификация JSON):
Трейт Deserializer имеет методы вида deserialize_type. Трейт Serializer имеет методы вида serialize_type. Что это значит? Это значит, что одно можно непосредственно сцепить с другим, и таким образом перегонять данные из одного формата данных, поддерживаемых serde, в другой, никогда не материализуя экземпляры соответствующих типов в памяти целиком. Собственно, именно это и делает serde-transcode.
Пример из документации (преттификация JSON):
extern crate serde;
extern crate serde_json;
extern crate serde_transcode;
use serde::Serialize;
use serde_json::{Serializer, Deserializer};
use std::io::{Read, Write, BufReader, BufWriter};
use std::fs::File;
fn main() {
let reader = BufReader::new(File::open("input.json").unwrap());
let writer = BufWriter::new(File::create("output.json").unwrap());
let mut deserializer = Deserializer::from_reader(reader);
let mut serializer = Serializer::pretty(writer);
serde_transcode::transcode(&mut deserializer, &mut serializer).unwrap();
serializer.into_inner().flush().unwrap();
}docs.rs
Deserializer in serde - Rust
A data format that can deserialize any data structure supported by Serde.
#prog #parsing
libphonenumber — библиотека для парсинга и форматирования телефонных номеров. Почему это необходимо? Ну, потому что телефонные номера — запутанная вещь.
libphonenumber — библиотека для парсинга и форматирования телефонных номеров. Почему это необходимо? Ну, потому что телефонные номера — запутанная вещь.
GitHub
GitHub - google/libphonenumber: Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international…
Google's common Java, C++ and JavaScript library for parsing, formatting, and validating international phone numbers. - google/libphonenumber