Блог*
I love Rust for letting me write self-describing code trait Т { type T; const TT: (Self::T, Self::T); } trait ТТ<T> { const Т: T; } trait Sеlf { const Sеlf: Self; } const fn t<T: Т<T = isize>>() -> isize { impl<T: ТТ<T>> Sеlf for T…
#prog #rust #моё
Что ж, наверное, стоит объяснить, а что это вообще за код такой.
Странно выглядят фрагменты вроде
Если переписать код, чтобы использовать лишь ASCII имена (и заодно привести его под принятые соглашения о наименованиях), то получится следующее:
Если вынести на верхний уровень impl-блоки (как я бы и сделал в реальном коде) и немного переупорядочить для ясности, то получится вот это:
ответ к загадке этого кода строчку, которая фактически является ассертом времени компиляции на то, что численное значение
Что ж, наверное, стоит объяснить, а что это вообще за код такой.
Странно выглядят фрагменты вроде
trait Sеlf {
const Sеlf: Self;
}
иconst fn t<T: Т<T = isize>>
, поскольку они вроде бы не должны компилироваться из-за совпадающих имён. Дело в том, что я использовал в Sеlf
кириллическую е
(и в имени трейта, и в имени ассоциированного типа), а в именах трейтов Т
и ТТ
— соответственно кириллическую Т
. Это разрешено с версии Rust 1.53. При этом компилятор выдаёт (помимо всего прочего) вот такое предупреждение на этот код:warning: the usage of Script Group `Cyrillic` in this crate consists solely of mixed script confusables
--> src/lib.rs:1:7
|
1 | trait Т {
| ^
|
= note: the usage includes 'Т' (U+0422), 'е' (U+0435)
= note: please recheck to make sure their usages are indeed what you want
= note: `#[warn(mixed_script_confusables)]` on by default
И также указывает на пары идентификаторов, которые могут быть перепутаны. Полезный компилятор, как ни крути.Если переписать код, чтобы использовать лишь ASCII имена (и заодно привести его под принятые соглашения о наименованиях), то получится следующее:
trait PairValue {
type T;
const PAIR_VALUE: (Self::T, Self::T);
}
trait GenericValue<T> {
const GENERIC_VALUE: T;
}
trait SelfValue {
const SELF_VALUE: Self;
}
const fn t<T: PairValue<T = isize>>() -> isize {
impl<T: GenericValue<T>> SelfValue for T {
const SELF_VALUE: Self = T::GENERIC_VALUE;
}
T::PAIR_VALUE.0 * T::PAIR_VALUE.1 + 20
}
const fn self_describing<T: SelfValue>() -> T {
impl<T: PairValue<T = isize>> GenericValue<isize> for T {
const GENERIC_VALUE: isize = t::<T>();
}
T::SELF_VALUE
}
enum The {
Answer = {
impl PairValue for isize {
type T = isize;
const PAIR_VALUE: (isize, isize) = (2, 11);
}
self_describing()
},
}
const _ASSERT: [(); 42] = [(); The::Answer as usize];
Вроде выглядит немного получше, но всё ещё запутанно. В Rust, как известно, (почти) всё является выражением. Различного рода top level определения (называемые item в reference) также могут быть использованы, как выражения, и при этом возвращают ()
. Очень много куда можно воткнуть impl
-блок — в частности, внутри функции и внутри выражения. В том числе внутри выражения для дискриминанта варианта enum
. Разумеется, при этом применяются обычные правила видимости: нельзя реализовать трейт, если трейт или тип, для которого они определяются, не видны в текущей области видимости, но сами impl-ы трейтов видны всюду, где виден сам трейт. Тут эти правила видимости, впрочем, не мешают.Если вынести на верхний уровень impl-блоки (как я бы и сделал в реальном коде) и немного переупорядочить для ясности, то получится вот это:
trait PairValue {
type T;
const PAIR_VALUE: (Self::T, Self::T);
}
impl PairValue for isize {
type T = isize;
const PAIR_VALUE: (isize, isize) = (2, 11);
}
trait GenericValue<T> {
const GENERIC_VALUE: T;
}
const fn t<T: PairValue<T = isize>>() -> isize {
T::PAIR_VALUE.0 * T::PAIR_VALUE.1 + 20
}
impl<T: PairValue<T = isize>> GenericValue<isize> for T {
const GENERIC_VALUE: isize = t::<T>();
}
trait SelfValue {
const SELF_VALUE: Self;
}
impl<T: GenericValue<T>> SelfValue for T {
const SELF_VALUE: Self = T::GENERIC_VALUE;
}
const fn self_describing<T: SelfValue>() -> T {
T::SELF_VALUE
}
enum The {
Answer = self_describing(),
}
const _ASSERT: [(); 42] = [(); The::Answer as usize];
В последней строчке мы находим The::Answer
является 42. Откуда берётся это значение? Выше Answer
присваивается значение вызова определённой парой строк выше функции self_describing
(кстати, использовать трейты на обобщённых параметрах в const fn стало возможным с версии 1.61). Но это обобщённая функция — так какой же тип там выводится?Telegram
Блог*
#prog #rust #rustreleasenotes
Да, да, я знаю, что я ленивая жягодица, не напоминайте.
Вышел Rust 1.53.0! Как обычно, я не буду разбирать релиз целиком, а выделю лишь то, что привлекло лично моё внимание.
Но начну я, пожалуй, с парочки вещей, которые мне…
Да, да, я знаю, что я ленивая жягодица, не напоминайте.
Вышел Rust 1.53.0! Как обычно, я не буду разбирать релиз целиком, а выделю лишь то, что привлекло лично моё внимание.
Но начну я, пожалуй, с парочки вещей, которые мне…
❤1😐1
Блог*
I love Rust for letting me write self-describing code trait Т { type T; const TT: (Self::T, Self::T); } trait ТТ<T> { const Т: T; } trait Sеlf { const Sеlf: Self; } const fn t<T: Т<T = isize>>() -> isize { impl<T: ТТ<T>> Sеlf for T…
Так вот, Rust reference гласит, что для default representation enum (а
Так какое же значение возвращается? Пойдёт снизу вверх.
|
| |
| | |
| |
| | |функция
| | |для
| |
|
Иными словами,
То есть "Ответ на главный вопрос жизни, вселенной и всего такого" — это 42, что мы и проверили в Rust на этапе компиляции.
The
является именно таковым, потому что на нём нет #[repr]
-атрибутов) дискриминанты имеют тип isize (что, однако, не мешает компилятору выбрать тип поменьше для представления enum). Таким образом, обобщённый параметр у self_describing
выводится равным возвращаемому типу, т. е. isize
.Так какое же значение возвращается? Пойдёт снизу вверх.
self_describing
принимает тип, ограниченный трейтом SelfValue
, и возвращает ассоциированную константу SELF_VALUE
;|
SelfValue
реализован для всех типов T
, реализующих GenericValue<T>
;| |
GenericValue<T>
реализован для всех типов, реализующих PairValue<T = isize>
;| | |
PairValue<T = isize>
реализован для isize
с PAIR_VALUE = (2, 11)
;| |
GenericValue<isize>
реализован для isize
с GENERIC_VALUE = t::<isize>()
;| | |функция
t
принимает тип, ограниченный PairValue<T = isize>
, и возвращает комбинацию от составляющих T::PAIR_VALUE
;| | |для
isize
функция t
возвращает 2 * 11 + 20 = 42;| |
<isize as GenericValue<isize>>::GENERIC_VALUE = 42
;|
<isize as SelfValue>::SELF_VALUE = 42
;self_describing::<isize>() == 42
;Иными словами,
enum The {
Answer = 42,
}
В последней строке создаётся неиспользуемая константа, тип которой задан, как массив длины 42, и которая инициализируется массивом длины The::Answer as usize
, то есть 42. Так как типы слева и справа совпадают, то код компилируется (и выдаёт предупреждение о неиспользуемых The
и self_describing
).То есть "Ответ на главный вопрос жизни, вселенной и всего такого" — это 42, что мы и проверили в Rust на этапе компиляции.
😐2
Блог*
#prog #rust #моё Что ж, наверное, стоит объяснить, а что это вообще за код такой. Странно выглядят фрагменты вроде trait Sеlf { const Sеlf: Self; } и const fn t<T: Т<T = isize>> , поскольку они вроде бы не должны компилироваться из-за совпадающих…
Этот пост спонсирован редактором ace (используемом на Rust playground).
ace — редактор со сломанным поиском.
ace — редактор со сломанным поиском.
GitHub
ace: searching whole words seems not to respect non-ASCII word boundaries · Issue #5232 · ajaxorg/ace
Describe the bug Using search functionality to look up whole words still finds query inside words if query consists of cyrrilic letters (and presumably other non-ASCII characters as well). Expected...
🤔1
#prog #video
Доклад от разработчиков IDE про превратности парсинга #cpp
youtube.com/watch?v=WfIr7lKT4Sk
Доклад от разработчиков IDE про превратности парсинга #cpp
youtube.com/watch?v=WfIr7lKT4Sk
YouTube
CppCon 2018: Timur Doumler & Dmitry Kozhevnikov “Parsing C++”
https://CppCon.org
—
Presentation Slides, PDFs, Source Code and other presenter materials are available at: https://github.com/CppCon/CppCon2018
—
C++ is a notoriously hard language to parse. Its grammar is highly context-dependent and ambiguous, and cannot…
—
Presentation Slides, PDFs, Source Code and other presenter materials are available at: https://github.com/CppCon/CppCon2018
—
C++ is a notoriously hard language to parse. Its grammar is highly context-dependent and ambiguous, and cannot…
🤣4❤1
@shitposting_three, пожалуйста, не выкладывай столько мемов, среди них много слишком хороших и в итоге весь Блог* в твоих репостах(
🤮5😭5❤🔥4😁2👍1
Блог*
Этот пост спонсирован редактором ace (используемом на Rust playground). ace — редактор со сломанным поиском.
Ты гляди-ка, даже отреагировали
GitHub
ace: searching whole words seems not to respect non-ASCII word boundaries · Issue #5232 · ajaxorg/ace
Describe the bug Using search functionality to look up whole words still finds query inside words if query consists of cyrrilic letters (and presumably other non-ASCII characters as well). Expected...
🤯3