1.83K subscribers
3.3K photos
132 videos
15 files
3.58K links
Блог со звёздочкой.

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

Небольшое прикольное комьюнити: @decltype_chat_ptr_t
Автор: @insert_reference_here
Download Telegram
Блог*
Я, конечно, совсем ни на что не намекаю, но вот вам номер моей карты: 4274 3200 5402 8520
Если каждый подписчик канала переведёт мне хотя бы по одному рублю, то я проснусь.
То ли #suckassstory, то ли #successstory, непонятно.

Игроки нашли хитровывернутый способ смотреть порно на только что вышедшей Playstation 5, даже не смотря на то, что у неё нет штатного браузера.

Смекал очка
#prog #rust

Дорогие подписчики, одна моя знакомая работает в стартапе, который работает со статическими анализаторами кода на Rust, в том числе Clippy. В настоящий момент они заняты созданием сводки линтов Clippy, в частности — тем, насколько их можно применить автоматически. Делают они это для того, чтобы в перспективе прикрутить возможности для автоматизации "ручных" линтов. К сожалению, в настоящий момент эту информацию, несмотря на шаблонность оформления линтов в Clippy, приходится искать в коде самостоятельно. Сводная информация по линтам, которую они собрали, размещена в этой (публично редактируемой) табличке на листе Clippy_Applicability. Помогите, пожалуйста, добрым людям!

Здесь определены основные функции для непосредственного вывода сообщений, функции вида span_lint. Для каждого линта нужно найти, с каким значением типа Applicability вызывается подобная функция, и внести это значение в колонку в таблице. Нужные значения разделяются запятыми, если линты могут быть сообщены с разной степенью автопригодности, и сообщаться через функцию вроде span_lint, который такой аргумент не принимает — в таком случае надо написать NotApplicable.

Я уже частично заполнил недостающие строки. Какие строки заполните вы?
#prog #meme от @iggisv9t
А я побуду Капитаном Очевидность и напомню, что хардкодить данные, токены, пароли и прочую опознавательную инфу плохо
Forwarded from Sviatoslav Iguana
Блог*
#prog #meme от @iggisv9t А я побуду Капитаном Очевидность и напомню, что хардкодить данные, токены, пароли и прочую опознавательную инфу плохо
Раз уж пошло такое дело, напомню, что у него есть чудесный канал @sv9t_channel. Машинное обучение, злые щитоспинки, непонятные графовые визуализации — в общем, всё, как вы любите.

Да, это #blogrecommendation
This media is not supported in your browser
VIEW IN TELEGRAM
Железнодорожная стрелка на Pilatus Railway, дороге с самым большим уклоном в мире, ведущей на гору Пилатус в Швейцарии. Нашёл в твиттере.
Если в поиске телеги на десктопе набрать тильду, то в строке поиска оно отобразится как дефис, но всё равно будет искать тильду в именах контактов/чатов/каналов
#video

Я хотел сделать интересный, содержательный пост про одну вещь на расте, но со мной случились полтора часа ночи и это. Прошу понять и простить.
#prog #rust

Хотел написать, что это ещё и #meme, но ведь это чистая правда
#prog #rust #article

Статья про то, как можно написать FFI-биндинги, сохранив при этом проверки borrow checker-а. К сожалению, без extern types сделать эргономично сложно.
Что нужно делать при начале разработки тулзы по работе? Правильно, искать подходящее название в греческой мифологии.
#prog #rust #article

Статья об использовании PGO для rustc. В двух словах: улучшения есть, и весьма заметные, но пока что непонятно, как это можно интегрировать с CI
#prog #rust #моё

Как сравнить в Rust две строки, игнорируя регистр символов? Строго говоря, используя лишь стандартную библиотеку — никак, поскольку перевод из одного регистра в другой зависит от локали, но давайте пока проигнорируем эту деталь и притворимся, что среди пользователей нашего приложения нет кого-то, кто живёт в Турции или Азербайджане (а также что у нас нет проблемы нормализования строк).

Итак, как же нам сравнить две строки, игнорируя регистр символов? Большинство Rust-программистов (особенно новичков) напишут что-то вроде этого:

fn equal_ignoring_case(a: &str, b: &str) -> bool {
a.to_lowercase() == b.to_lowercase()
}

Правильное ли это решение? НЕТ, НЕПРАВИЛЬНОЕ, КТО ВООБЩЕ ТАК ПИШЕТ Технически оно верное, но оно делает много лишней работы. Что тут происходит? Сначала под первую строку выделяется место в куче, которое заполняется проходом по строке с преобразованиями по довольно нетривиальным правилам, во время которых выполняется бинарный поиск по захардкоженным таблицам, затем то же самое происходит для второй строки, и только после этого строки сравниваются друг с другом. Всё это происходит даже в том случае, если строки большие и даже если строки различаются уже первым символом.

Можно ли сделать лучше? Разумеется: мы можем преобразовывать символы в нижний регистр не сразу все, а на лету, по требованию. Используя стандартную библиотеку, легко написать подобную функцию, которая ещё и не выделяет память в куче:

fn equal_ignoring_case(a: &str, b: &str) -> bool {
a.chars().flat_map(char::to_lowercase).eq(b.chars().flat_map(char::to_lowercase))
}

(тут используется почему-то малоизвестный метод Iterator::eq, который проверяет, что два итератора выдают равные последовательности элементов)

А что делать, если одна из строк заведомо содержит лишь ASCII символы (например, это литерал для какого-нибудь формата разметки)? В таком случае мы можем игнорировать юникодные правила преобразования и проверять лишь равенство ASCII-символов без учёта регистра, что значительно более простая задача. Мы можем эксплуатировать тот факт, что строка — это набор байт, проверять строки побайтово, перед этим ещё и проверить, что у них одинаковая длина... Или же не переизобретать велосипед и воспользоваться готовым методом str::eq_ignore_ascii_case.

Немного усложним задачу: теперь нужно определить, что одна строка начинается с другой, игнорируя регистр. Решение в лоб:

fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {
s.to_lowercase().starts_with(&prefix.to_lowercase())
}

, но оно не оптимально по тем же причинам. К сожалению, трюк с Iterator::eq здесь не подойдёт, потому что этот метод может вернуть true в том случае, если s короче prefix и потому не может его содержать. По аналогичным причинам не подойдёт Iterator::zip. К сожалению, придется написать немного кода самому, с ручными вызовами next:

fn starts_with_ignoring_case(s: &str, prefix: &str) -> bool {
let mut s = s.chars().flat_map(char::to_lowercase);
let mut prefix = prefix.chars().flat_map(char::to_lowercase);
while let Some(s_ch) = s.next() {
match prefix.next() {
Some(p_ch) => if s_ch != p_ch {
return false
},
None => return true, //префикс закончился, а все символы до это совпадали
//значит, строка содержит префикс
}
}
//закончились символы в строке, и они все совпали с символами в префиксе
true
}

Разумеется, и тут применима оптимизация, если одна из строк состоит только из ASCII-символов:

fn starts_with_ignoring_ascii_case(s: &str, prefix: &str) -> bool {
s.get(..prefix.len()).map_or(false, |start| start.eq_ignore_ascii_case(prefix))
}

Почему я решил об этом написать? Да потому что меня бесит, когда я вижу подобный настолько неоптимальный код. Так что можете считать, что это #бомбёжкипост.