Ищу интересные магические предметы для персонажей в ДнД.
Вижу "Сфера разрыва донжона".
Ну-ка, ну-ка, как оно там донжоны разрывает?
Donjon’s Sundering Sphere
А я надеялся
Вижу "Сфера разрыва донжона".
Ну-ка, ну-ка, как оно там донжоны разрывает?
😁1
А вот интересно. Есть ли достаточно черная магия, которая позволит написать такие две функции.
заметьте, что const.
По сути я хочу знать, а функция с неким типом вообще где-то в коде вызывается?
И получить
const fn IsCalledWith<T>() -> bool { ... }
fn CallItWith<T>() { .. }
заметьте, что const.
По сути я хочу знать, а функция с неким типом вообще где-то в коде вызывается?
И получить
const bool
This media is not supported in your browser
VIEW IN TELEGRAM
Давненько ничего я не выкладывал.
Поэтому вот вам видео с геометрической либой.
Первая операция - отражение.
Планируется полный комплект геометрической алгебры для 2д и 3д.
Тулза на коленке сделана для отладки.
Поэтому вот вам видео с геометрической либой.
Первая операция - отражение.
Планируется полный комплект геометрической алгебры для 2д и 3д.
Тулза на коленке сделана для отладки.
🔥8
This media is not supported in your browser
VIEW IN TELEGRAM
Теперь можно отражать и точки и линии в линиях, а потом в отраженных отражать
🔥2👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Как долго написать еще и отражение точек и линий в точке?
Я его написал после того как отправил прошлое видео
Я его написал после того как отправил прошлое видео
❤1
This media is not supported in your browser
VIEW IN TELEGRAM
Умножаем две линии друг на друга и получаем Motor. Который вращает объекты вокруг точки пересечения линий на удвоенный угол между ними.
А что если они параллельные?
Вращение превращается в линейное движение на удвоенное расстояние между линиями. А формула все та же.
А что если они параллельные?
Вращение превращается в линейное движение на удвоенное расстояние между линиями. А формула все та же.
❤3
This media is not supported in your browser
VIEW IN TELEGRAM
Обычное умножение линий дает мотор, который сдвигает на удвоенное растояние и поворачивает на удвоенный угол между линиями.
Что ж, гораздо удобнее брать от этого умножения квадратный корень.
Теперь, как вы видите, точки следуют за второй линией в той же конфигурации, в какой они находятся у первой линии.
Что ж, гораздо удобнее брать от этого умножения квадратный корень.
Теперь, как вы видите, точки следуют за второй линией в той же конфигурации, в какой они находятся у первой линии.
Начинаю регулярную рубрику Rust Tips 🔧
Сегодня - о замечательной функции
Она позволяет превратить
Вот классический пример, где как новичики, так и ветераны спотыкаются о borrow checker
❌ Передать
Здесь мы можем использовать магию
Обернем ссылку на
🎉 И вуаля - всё работает! 🎉
Бонус для внимательных:
Теперь
Так что можно тот же трюк использовать что бы передать замыкание, которое что-то мутирует в функцию, которая принимает
Сегодня - о замечательной функции
Cell::from_mut
Она позволяет превратить
&mut T
в &Cell<T>
, что все еще позволяет изменять T
, но ее разрешается расшаритьВот классический пример, где как новичики, так и ветераны спотыкаются о borrow checker
let mut counter = 0;
let mut inc = || counter += 1;
let print = || println!("{}", counter); // cannot borrow `counter` as immutable because it is also borrowed as mutable
inc();
inc();
print();
❌ Передать
&mut
в inc
и одновременно &
в print
нельзя. ❌Здесь мы можем использовать магию
Cell::from_mut
, не изменяя окружающий код.Обернем ссылку на
counter
и раздадим в замыкания.
let mut counter = 0;
let cell = Cell::from_mut(&mut counter);
let inc = || cell.set(cell.get() + 1);
let print = || println!("{}", cell.get());
inc();
inc();
print();
🎉 И вуаля - всё работает! 🎉
Бонус для внимательных:
Теперь
inc
теперь реализует и Fn
.Так что можно тот же трюк использовать что бы передать замыкание, которое что-то мутирует в функцию, которая принимает
Fn
без Send
.👍19❤5
Сегодняшний Rust Tip об очень полезной функции -
Когда у вас уже есть объект и нужно заменить его клоном другого значения - не спешите писать
Вместо этого используйте:
Такой вызов позволяет переиспользовать существующее значение - особенно ресурсы вроде памяти.
Это особенно эффективно при клонировании
И, конечно, это работает транзитивно.
Вложенный
При использовании
Но если вы реализуете
Ведь реализация по умолчанию просто делает
Если ваш тип не
Аналогичная оптимизация есть и у трейта
Для типов вроде
Такие небольшие улучшения могут сэкономить вам годзиллионы процессорных циклов.
И при профилировании вы будете реже видеть, как ваше приложение тратит 90% времени на клонирование и выделение памяти.
Clone::clone_from
.Когда у вас уже есть объект и нужно заменить его клоном другого значения - не спешите писать
a = b.clone()
.Вместо этого используйте:
a.clone_from(&b)
.Такой вызов позволяет переиспользовать существующее значение - особенно ресурсы вроде памяти.
Это особенно эффективно при клонировании
Box
, Vec
, String
и прочих.И, конечно, это работает транзитивно.
Вложенный
Vec<T>
будет клонировать T
с помощью clone_from
для существующих элементов.При использовании
#[derive(Clone)]
, компилятор автоматически вызывает clone_from
для всех полей.Но если вы реализуете
Clone
вручную - подумайте, не стоит ли также переопределить clone_from
.Ведь реализация по умолчанию просто делает
*self = other.clone()
.Если ваш тип не
Copy
, clone_from
почти наверняка окажется дешевле.Аналогичная оптимизация есть и у трейта
ToOwned
.Для типов вроде
str
, Path
или [T]
используйте ToOwned::clone_into(&mut target)
вместо target = value.to_owned()
.Такие небольшие улучшения могут сэкономить вам годзиллионы процессорных циклов.
И при профилировании вы будете реже видеть, как ваше приложение тратит 90% времени на клонирование и выделение памяти.
👍16❤1
Свежий Rust Tip по свежему stable API
С версии 1.86 в stable стал доступен метод
Который позволяет получить мутабельные ссылки на разные элементы слайса одновременно.
Разность проверяется методом и при пересечении возвращается ошибка.
Равно как и при индексе вне диапазона.
Вот как его можно использовать
Так же как
Так как в метод передается массив, то все должны быть одного типа.
Похожим методом обзавелся и
Для любителей unsafe есть версии
Удачного вам мулти-индексирования.
С версии 1.86 в stable стал доступен метод
slice::get_disjoint_mut
. Который позволяет получить мутабельные ссылки на разные элементы слайса одновременно.
Разность проверяется методом и при пересечении возвращается ошибка.
Равно как и при индексе вне диапазона.
Вот как его можно использовать
let mut array = [10, 20, 30, 40, 50];
let [a, b, c] = array.get_disjoint_mut([1, 3, 4]).expect("Index overlap");
*a += 100; // 20 -> 120
*b += 100; // 40 -> 140
*c += 100; // 50 -> 150
Так же как
get
, можно использовать Range
, RangeInclusive
, RangeFrom
, RangeTo
и RangeFull
, хотя все кроме первых двух для этого метода вряд ли пригодятся.Так как в метод передается массив, то все должны быть одного типа.
let [a, b, c] = array.get_disjoint_mut([0..2, 2..3, 3..5]).expect("Range overlap");
a.copy_from_slice(&[9, 10]);
b.copy_from_slice(&[11]);
c.copy_from_slice(&[12, 13]);
Похожим методом обзавелся и
HashMap
, но там вместо возвращения ошибки метод паникует, и возвращает массив Option
.let mut map = HashMap::from([
("a", 1),
("b", 2),
("c", 3),
]);
let [oa, ob] = map.get_disjoint_mut(["a", "b"]);
if let (Some(a), Some(b)) = (oa, ob) {
*a += 10;
*b += 20;
}
Для любителей unsafe есть версии
*_unchecked
этих методов, которые пропускают проверку непересечения индекстов/диапазонов/ключей.Удачного вам мулти-индексирования.
🔥9👍3
Придумывал глупую шутку про программирование.
Варианты:
Варианты:
1. Добавил обработку краевых условий. Теперь не работает на нормальных.
2. Поймал исключение. До сих пор держу.
3. Поднял прод. Теперь он надо мной.
4. Вызвал функцию. Она не пришла.
5. Написал универсальную функцию. Не подошла ни к одному случаю.
6. Придумал абстракцию. Теперь боюсь к ней прикасаться.
7. Вынес повторяющийся код. Повторяется в другом месте.
8. Написал комментарий. Теперь только он и понятен.
🔥13
Rust Tip для тех кто отлаживает UB в своем unsafe коде в 2 часа ночи.
Делайте маленькие unsafe блоки. Стремитесь к одному выражению.
Всегда сопроводите комментарием, почему это safe.
Используйте линт, что б заставить себя писать unsafe блоки в unsafe функциях, если вы на старой версии компилятора.
Не пишите unsafe, если можете обойтись.
Делайте маленькие unsafe блоки. Стремитесь к одному выражению.
Всегда сопроводите комментарием, почему это safe.
Используйте линт, что б заставить себя писать unsafe блоки в unsafe функциях, если вы на старой версии компилятора.
Не пишите unsafe, если можете обойтись.
👍12
This media is not supported in your browser
VIEW IN TELEGRAM
Добрался сделать умножение моторов на скаляр. Что позволяет интерполировать и экстраполировать.
🔥3
Rust Tip дня: матчинг слайсов.
В Rust можно элегантно извлекать элементы из слайсов с помощью паттерн-матчинга:
Извлечение с одним вариантом.
Извлечение с ранним возвратом при ошибке матчинга.
Сила pattern matching раскрывается в полной мере, когда вы:
* избегаете ручного индексирования,
* делаете распаковку данных декларативной,
* явно документируете формат входа через структуру паттерна.
Приятного вам матчинга.
В Rust можно элегантно извлекать элементы из слайсов с помощью паттерн-матчинга:
match input {
[0xFF, rest @ ..] => println!("Starts with 0xFF, then {:?}", rest),
[first, second, .., last] => println!("Start: {first:#X}, {second:#X}, end: {last:#X}"),
[.., last] => println!("Ends with {last:#X}"),
[] => println!("Empty slice"),
}
Извлечение с одним вариантом.
if let [a, b, c] = input {
println!("Exactly three elements: {a}, {b}, {c}");
}
Извлечение с ранним возвратом при ошибке матчинга.
let [first, second, rest @ ..] = input else {
panic!("Expected at least two elements");
};
println!("Parsed: {first}, {second}, rest = {:?}", rest);
Сила pattern matching раскрывается в полной мере, когда вы:
* избегаете ручного индексирования,
* делаете распаковку данных декларативной,
* явно документируете формат входа через структуру паттерна.
Приятного вам матчинга.
👍20❤2
Rust Tip для чернокнижников.
Drop-check будет считать, что
Еще одно важное отличие это авто-трейты.
Если
Следует учитывать, что
Удачной вам охоты на фантомные данные 👻
PhantomData<T>
vs PhantomData<fn() -> T>
- не одно и то жеPhantomData<T>
указывает на семантику владения T
.PhantomData<fn() -> T>
- лишь на то что где-то будет использоваться этот T
.Drop-check будет считать, что
PhantomData<T>
может вызывать Drop
у T
, а PhantomData<fn() -> T>
- не будет.Еще одно важное отличие это авто-трейты.
PhantomData<T>
наследует их от T
, а вот PhantomData<fn() -> T>
нет.Если
T
будет !Send
или !Sync
, то в первом случае и ваш тип будет. А в случае функции - нет. Указатели на функции Send
, Sync
, Unpin
и прочие Freeze
независимо от типов аргументов и возвращаемого типа.#[derive(Default)]
struct Foo<T>(PhantomData<T>);
#[derive(Default)]
struct Bar<T>(PhantomData<fn() -> T>);
let foo: Foo<Rc<u8>> = Foo::default();
let bar: Bar<Rc<u8>> = Bar::default();
std::thread::spawn(|| { drop(foo); }); // error: `Rc<u8>` cannot be sent between threads safely
std::thread::spawn(|| { drop(bar); }); // success!
Следует учитывать, что
PhantomData<fn(T)>
переворачивает ковариантность, так что его стоит использовать когда именно это и нужно.Удачной вам охоты на фантомные данные 👻
🔥17👍3❤2
Канал перевалил за 300 подписчиков!!!
🎉 Ура-ура-ура 🎉
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥24👍5🍾5❤1
Rust Tip дня:
🔹
Изолирует редкий или громоздкий код от горячего пути.
Горячий путь меньше - лучше локальность - больше производительность.
✅ Используй, если:
код вызывается редко.
хочется сократить размер inlined функций;
slow path.
🔹
Помечает функцию как исключительно редкую.
Позволяет релоцировать код для лучшей производительности горячего кода.
✅ Используй, только если:
вызов происходит <1% случаев;
код отрабатывающий только на разогреве и не используемый позже.
функция вызывается только в исключительных случаях.
⚠️ Не ставь
💡 Некоторые функции и макросы, такие как
Для
Бонус.
Если вам привычны
На stable вы можете легко их реализовать сами - просто сделайте вызов пустой холодной функции.
#[inline(never)]
и #[cold]
- когда использовать?🔹
#[inline(never)]
Изолирует редкий или громоздкий код от горячего пути.
Горячий путь меньше - лучше локальность - больше производительность.
✅ Используй, если:
код вызывается редко.
хочется сократить размер inlined функций;
slow path.
fn some_threaded_algo(rw: &RwLock<Foo>) -> Bar {
let read = rw.read();
match try_do_stuff(&*read) { // may fail with only shared ref
Ok(bar) => bar,
Err(_) => {
drop(read);
slow_path(rw)
}
}
#[inline(never)]
fn slow_path(rw: &RwLock<Foo>) -> Bar {
let mut write = rw.write();
do_stuff(&mut *write) // may not fail with exclusive ref
}
🔹
#[cold]
Помечает функцию как исключительно редкую.
Позволяет релоцировать код для лучшей производительности горячего кода.
✅ Используй, только если:
вызов происходит <1% случаев;
код отрабатывающий только на разогреве и не используемый позже.
функция вызывается только в исключительных случаях.
⚠️ Не ставь
#[cold]
, если функция вызывается даже изредка - даже 1–2% уже много.💡 Некоторые функции и макросы, такие как
panic!()
, сами по себе уже #[cold]
, дополнительная аннотация не требуется.Для
slow_path
из примера выше можно добавить #[cold]
, если необходимость в экслюзивном локе это исключительная редкость.Бонус.
Если вам привычны
likely
и unlikely
, что бы помечать ветки как холодные, они есть в nightly.На stable вы можете легко их реализовать сами - просто сделайте вызов пустой холодной функции.
#[inline(always)]
fn likely(b: bool) -> bool {
if b {
true
} else {
cold_path();
false
}
}
#[inline(always)]
fn unlikely(b: bool) -> bool {
if b {
cold_path();
true
} else {
false
}
}
#[inline(always)]
#[cold]
fn cold_path() {}
❤5👍2😱1💯1
Rust Tip мини
Остерегайтесь расставлять #[inline(always)].
#[inline] достаточно для того что бы компилятор заинлайнил функцию, если сочтет нужным (без него кросс библиотечные вызовы могут не инлайниться).
#[inline(always)] может привести к тому что код слишком разбухнет и нарушится локальность.
Дайте оптимизатору выполнять его работу.
Остерегайтесь расставлять #[inline(always)].
#[inline] достаточно для того что бы компилятор заинлайнил функцию, если сочтет нужным (без него кросс библиотечные вызовы могут не инлайниться).
#[inline(always)] может привести к тому что код слишком разбухнет и нарушится локальность.
Дайте оптимизатору выполнять его работу.
🤝10💯1