ch
Feedback
Блог*

Блог*

前往频道在 Telegram

Блог со звёздочкой. Много репостов, немножко программирования. Небольшое прикольное комьюнити: @decltype_chat_ptr_t Автор: @insert_reference_here

显示更多
1 947
订阅者
-224 小时
+17
-130
帖子存档
photo content

#tips Не используйте для подписи коммитов на Github GPG-ключи, у которых указан e-mail, но не имя — Github почему-то считает, что к этим ключам не прикреплены e-mail (The email in this signature doesn’t match the committer email) и потому отказывается верифицировать коммиты, подписанные этим ключом.

А для того, чтобы оно всё-таки работало, нужно, чтобы реализовали impl Fn() -> impl Trait in return position (привет, Вафель) и, желательно, синтаксис для явного написания замыкания с полиморфизмом высшего ранга. И то, кстати, не факт, что сработает, поскольку в силу того, что возвращаемое замыкание содержит &'o Order, это замыкание, вообще говоря, должно принимать ссылку на строковой слайс не с произвольным временем жизни, а живущую не менее, чем 'o, а ограничение на времена жизни в higher-ranked trait bounds не работают даже для fn pointers.

fn with_order<'o>(order: &'o Order) -> impl (for<'a> Fn(&'a str) -> (impl Iterator<Item = usize> + 'a + 'o)) + 'o Real Rust code written by real programmers (which doesn't actually work)

#prog #meme #c

photo content

...Или мы можем подрубить nightly и абстрагироваться от конкретной разновидности заимствующих ключей при помощи GAT-ов!
#![feature(generic_associated_types)]

Так как непосредственно конструктор типа мы передать не можем, мы передадим некий маркерный тип, к которому при помощи трейта прицепим ассоциированными типом нужный нам тип ключа: trait BorrowedKeyFamily { type Key<'a>: Ord + 'a; } Теперь нам нужен этот самый маркерный тип написать и связать его с кортежем ссылок:
struct PairRef<T, U: ?Sized>(std::marker::PhantomData<(T, U)>);

impl<T, U> BorrowedKeyFamily for PairRef<T, U>
where
    T: Ord + 'static,
    U: Ord + 'static + ?Sized,
{
    type Key<'a> = (&'a T, &'a U);
}

Как обычно, типовые сигнатуры начинают заниматьь больше места, чем сам код. Что ж, используем всё это для нового метода в SliceExt: trait SliceExt<T> { // ... fn sort_by_borrowed_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K::Key<'_>, K: BorrowedKeyFamily; } impl<T> SliceExt<T> for [T] { // ... fn sort_by_borrowed_key<K, F>(&mut self, mut f: F) where F: FnMut(&T) -> K::Key<'_>, K: BorrowedKeyFamily { self.sort_by(|a, b| f(a).cmp(&f(b))); } } Кстати, благодаря анонимному лайфтайму нам не пришлось писать F: for<'a> FnMut(&'a T) -> K::Key<'a> (и, признаться честно, я удивлён, что для GAT это работает). Теперь напишем сортировку с только что сделанным методом: arr.sort_by_borrowed_key(|d| (&d.name, &d.bytes)); Всем спасибо, все сво... error[E0282]: type annotations needed --> src/lib.rs:12:9 | 12 | arr.sort_by_borrowed_key(|d| (&d.name, &d.bytes)); | ^^^^^^^^^^^^^^^^^^^^ cannot infer type for type parameter `K` declared on the associated function `sort_by_borrowed_key` А, компилятор не может понять, что за маркерный тип тут используется. Что ж, неприятно, но вполне логично — мы теоретически можем написать ещё один тип и реализовать для него BorrowedKeyFamily с парой ссылок (вот, кстати, место, где пригодился бы аналог FunctionalDependencies из GHC). Придётся воткнуть турборыбу: arr.sort_by_borrowed_key::<PairRef<_, _>, _>(|d| (&d.name, &d.bytes)); Выглядит уже не так клёво. Вдобавок, у нашего кода есть одно досадное и неочевидное ограничение. Посмотрим ещё раз на ограничения на тип Key: type Key<'a>: Ord + 'a; То есть что бы ни лежало в Key<'a>, оно должно жить как минимум 'a. А у нас 'a может быть произвольным. Для T и U в составе пары это фактически выливается в ограничение for<'a> 'a, что эквивалентно 'static по определению. На практике это означает, что мы не сможем класть в ключ строковые слайсы, что резко ограничивает применимость подхода. ...Ну, зато мы выпендрились GAT-ами. Как всегда, весь код в гисте.

#prog #rust #моё Пусть у нас есть слайс из вот таких структур: struct Data { name: String, whatever: u32, bytes: Vec<u8>, } , и нам надо отсортировать слайс по полю name. Казалось бы, плёвое дело: arr.sort_by_key(|d| &d.name); Но компилятор ругается: error: lifetime may not live long enough --> src/lib.rs:8:21 | 8 | arr.sort_by_key(|d| &d.name); | -- ^^^^^^^ returning this value requires that `'1` must outlive `'2` | || | |return type of closure is &'2 String | has type `&'1 Data` В чём дело? Посмотрим на сигнатуру sort_by_key: fn sort_by_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> K, K: Ord, Обратите внимание, параметр K не параметризован никакими временами жизни и потому считается независимым от переданной ссылки на T. Очевидно, в нашем случае это не так: ссылка на поле структуры не может жить дольше ссылки на структуру целиком. Что делать? Можно, конечно, клонировать строку, но делать аллокацию в памяти только ради того, чтобы сравнить данные и тут же их деаллоцировать — это расточительно. Проще использовать sort_by, который требует функцию, возвращающую Ordering: arr.sort_by(|a, b| a.name.cmp(&b.name)); Окей, это работает, но выглядит уже не очень. Нам приходится повторять себя, да и идея "сравнить по name" уже не так хорошо читается. А если на потребуется сравнивать сначала по name, а потом по bytes? arr.sort_by(|a, b| (&a.name, &a.bytes).cmp(&(&b.name, &b.bytes))); Ох, выглядит так себе, от обилия скобочек немного рябит в глазах. А если переписать на методах Ordering? arr.sort_by(|a, b| a.name.cmp(&b.name).then_with(|| a.bytes.cmp(&b.bytes))); Лучше особо не стало. И, кстати, что там, что там велик соблазн скопипастить выражения для a и заменить на b — великолепный способ, чтобы забыть в каком-то месте поменять. Мы можем сделать лучше! Упрячем sort_by в одном месте и выставим интерфейс, который принимает функцию для вынимания ключа: trait SliceExt<T> { fn sort_by_ref_key<K, F>(&mut self, f: F) where F: FnMut(&T) -> &K, K: Ord + ?Sized; // почему "?Sized"? } impl<T> SliceExt<T> for [T] { fn sort_by_ref_key<K, F>(&mut self, mut f: F) where F: FnMut(&T) -> &K, K: Ord + ?Sized, { self.sort_by(|a, b| f(a).cmp(&f(b))); } } Теперь мы можем красиво отсортировать по имени: arr.sort_by_ref_key(|d| &d.name); Не менее красиво мы можем отсортировать по имени и по байтам... А нет, погодите, не можем — это потребует возвращать пару ссылок, а кортеж из ссылок ссылкой не является ауф. Так что до новых встреч.

#prog #rust #article И ещё немного про мьютексы в Rust. Why Rust mutexes look like they do (перевод)

cat вступил в профсоюз и его теперь нельзя уволить с его работы на первом месте в пайплайне

#prog #quotes

Задал ребенку блестящее (не могу кривить душой!) задание. Мы решили (так как беседуем с ней раз в неделю уже третий год), что пора обсуждать литературу. Решили начать с мифа. Ученица начиталась терминологии, объяснила мне, что такое космогонический миф, а что такое онтологический. Было очень здорово, хотя слова эти по первости она произносила по слогам. Мы приводили друг другу примеры, пересказывали мифы разных народов и оба собой глубоко гордились. И тут ученица задала блестящий вопрос — а выросли ли мы уже, все человечество, из мифов? Я задумался и предположил, что нет. В качестве примера я привел детскую мифологию, объясняющую мир. Например, мне в деревенском детстве объясняли, что убивать пауков нельзя. Если убьешь паука, то Бог плачет и идет дождь. Девочка очень обрадовалась и стала толковать. Пауки полезны, они очищают дом от насекомых, их нельзя убивать; но надо объяснить, почему. Я к этому добавил, что рассказывали мне это про пауков-крестовиков, у которых на спинке буквально крест — отсюда и мотив Бога. Ученица в качестве своего детского мифа привела историю про аиста, приносящего детей. И тут у меня в голове щелкнуло. Я поразмыслил и предложил ей провести исследование. Буквально расспросить одноклассников о мифах, в которые они верили в детстве и с помощью которых им объяснили мир. А еще лучше — расспросить родителей о том, во что они верили в детстве. Ученица прямо самостоятельно и без напоминания записала все в тетрадочку и сообщила, что это очень остроумное задание. Я не мог не согласиться и решил ей польстить. — Вообще-то это можно даже назвать антропологическим исследованием! — важно сказал я. Девочка округлила глаза и тут же записала такое важное и звучное выражение. Буду держать вас в курсе.

Ввиду последних событий, вероятно, будут банить числа 86 и 90

Существует известная проблема из области социологии: как получить более или менее честные данные в количественном исследовании, если респонденты не хотят/боятся/стыдятся отвечать честно. И вот случайно наткнулся на простой и изящный подход в духе differential privacy. TL;DR - формируем список из N утверждений, делим респондентов на две группы, одной показываем все N утверждений, другой - все, кроме того самого чувствительного. Вопрос формулируется как "с каким количеством утверждений (неважно, каких именно) вы согласны", и по разнице между группами легко вывести истинную поддержку. Должно подойти не только для опросов про войну, но и для user research.

Repost from N/a
«У России три пути: вебкам, закладки и айти» > OnlyFans приостанавливает работу аккаунтов из России > полиция Германии ликвидирует Гидру > Интел полностью останавливает работу в России У России… нет путей?

#prog #rust #article My First Clippy Lint

Repost from Чылік
Забалтывание
+4
Забалтывание