Блог* – Telegram
1.9K subscribers
3.46K photos
135 videos
15 files
3.69K links
Блог со звёздочкой.

Много репостов, немножко программирования.

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
#prog

TIL, что мьютексы из POSIX threads нельзя перемещать.

Once a mutex is created, it cannot be validly copied or moved to a new location. If the mutex is copied or moved to a new location, the new object is not valid and should not be used. Any attempt to use the invalid object will produce unpredictable results.

Здесь. Что ж, это объясняет, почему мьютексы из стандартной библиотеки Rust боксят нативные мьютексы.
Forwarded from Гоферы думают
Forwarded from You Had No Job
Поправь опечатку:

• Хейт миддл: всё технологии говно, коллеги — чудаки, раньше было лучше
• Хайп миддл: перепишет фронт на Расте, устал от микросервисов и использует макросервисы
• Найт миддл: обожает томатный смузи, никогда не появлялся на утреннем дейли
В программировании я придерживаюсь SOLID:
S - Just
O - Rewrite
L - It
I - In
D - Rust
документация к git, идентичная натуральной: https://git-man-page-generator.lokaltog.net/
#prog #go

Замечательный канал, всем рекомендую.

@golang_the_best
— Мне киндл постоянно какую-то дичь советует, но сегодня он превзошёл себя

#cpp #трудовыебудни
Forwarded from You Had No Job
"Зря-зря" говорит техдир
Forwarded from <илья as Человек> (ilya sheprut)
Девочки, переписываем программы на японский 💅
Окей, продолжения не было слишком долго. Напишу завтра
Разработчик СУБД не выкидывает мусор, а помечает его как удалённый
Блог*
Ох, постараюсь уложить это в голове. Есть ещё что-то, что нужно знать о замыканиях? Да. Иногда требуется одно и тоже замыкание передать в качестве аргумента в несколько функций. Клонировать в этом случае не получится, потому что замыкание является клонируемым…
#prog #rust #моё

Хроники замыканий

Есть ещё кое-что, что можно сказать про замыкания.

Пожалуй, первое, с чего надо начать — так это с того, что, несмотря на то, что замыкания — это автоматически генерируемые структуры, реализующие определённые трейты, реализовать их самому для своих типов нельзя — по крайней мере, на стабильной версии Rust. Для того, чтобы определить один из Fn*-трейтов для своего типа, нужно активировать две фичи. Первая — fn_traits — позволяет написать определение трейта в обычном виде, а не в засахаренном Fn(Foo) -> Bar, как обычно. Вторая — unboxed_closures — позволяет определять функции с ABI rust-call, которое имеют методы Fn*-трейтов. Если мы их используем, то мы можем сделать то, что невозможно на текущей стабильной версии Rust: перегрузку функции по количеству аргументов. Причина, по которой эти трейты не стабилизированы, видимо, состоит в том, что им в качестве ти́пового параметра требуется не произвольный тип, а кортеж типов аргументов. Это выглядит несколько неловко на фоне отсутствия вариадических обобщённых типов, особенно для функции от одного аргумента — его приходится заключать в одноместный кортеж.

Стоп, в Rust есть одноместный кортеж?!

Да. Он объявляется одинаково на уровне термов и на уровне типов: (x,)

Ужас какой. А что ещё можно сказать про замыкания?

Надо сказать, что замыкания являются, в сущности, обычными типами, которые отличаются в основном анонимностью. И на них, в частности, нужно в некоторых ситуациях накладывать нужные ограничения. Рассмотрим в качестве примера функцию, которая принимает некоторый счётчик и возвращает замыкание, которое инкрементирует этот счётчик на каждый вызов. Для простоты пусть это будет просто u32. Кажется, что можно написать вот так:

fn make_incrementer(counter: &mut u32) -> impl FnMut() {
move || *counter += 1
}

, однако этого недостаточно. Дело в том, что возвращаемое замыкание хранит мутабельную ссылку, которая имеет своё время жизни, но это никак не отражено в сигнатуре. Трейты в сигнатурах без явно указанных ограничений времени получают ограничение 'static, что в данном случае явно неверно.

А разве компилятор не может сам догадаться, как надо?

Нет. Компилятор проверяет правильность расстановки времён жизни, анализируя лишь сигнатуру функции, а не её тело.

Хорошо. Так как нам заставить этот код компилироваться?

Указать явно, что возвращаемое замыкание не может пережить захваченную ссылку. Мы можем сделать это, введя для времени жизни имя и приписав его ссылке и возвращаемому замыканию:

fn make_incrementer<'a>(counter: &'a mut u32) -> impl FnMut() + 'a { // ...

...или же мы можем побыть ленивыми и, последовав совету компилятора, навернуть анонимное время жизни:

fn make_incrementer(counter: &mut u32) -> impl FnMut() + '_ { // ...

Ясно. А для чего там move?

Это связано с тем, как замыкания в Rust работают с захваченными значениями (т. е. со значениями, объявленными снаружи самого замыкания). По умолчанию замыкания захватывают переменные по ссылке (то есть сгенерированный анонимный тип содержит ссылки на эти значения) — мутабельной или иммутабельной, в зависимости от того, как они используются внутри тела замыкания. Использование ключевого слова move переопределяет это поведение по умолчанию и заставляет замыкание захватывать переменные по значению (т. е. перемещает их в замыкание). Если его убрать, то make_counter не будет компилироваться: аргумент counter — фактически, локальная переменная — захватывается по ссылке, время жизни которой ограничено скоупом make_counter, поэтому вернуть такое замыкание за пределы порождающей его функции нельзя.

Так, стоп, так counter захватывается по ссылке или по значению?

В правильном или неправильном варианте?

...В правильном

По значению.

Но...

Просто в данном случае само захватываемое значение является ссылкой.

А, я понял. Кажется...

Ничего, это действительно поначалу немного сбивает с толку.

Что ж, это всё, что ты хотел рассказать про замыкания?

Всё? ВСЁ? АХАХХАХАХХАХХА

О_о