Ищу интересные магические предметы для персонажей в ДнД.
Вижу "Сфера разрыва донжона".
Ну-ка, ну-ка, как оно там донжоны разрывает?
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
этих методов, которые пропускают проверку непересечения индекстов/диапазонов/ключей.Удачного вам мулти-индексирования.
🔥10👍3
Придумывал глупую шутку про программирование.
Варианты:
Варианты:
1. Добавил обработку краевых условий. Теперь не работает на нормальных.
2. Поймал исключение. До сих пор держу.
3. Поднял прод. Теперь он надо мной.
4. Вызвал функцию. Она не пришла.
5. Написал универсальную функцию. Не подошла ни к одному случаю.
6. Придумал абстракцию. Теперь боюсь к ней прикасаться.
7. Вынес повторяющийся код. Повторяется в другом месте.
8. Написал комментарий. Теперь только он и понятен.
🔥14
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