Forwarded from Agagagagagagagaggagagaggaggaggaga
Вот сейчас все орут с Яндекса, а они дождутся, когда все самые кривые места разойдутся мемасами по телеге, и отрефакторят все косяки, не вложив ни часа в анализ. Stonks, не иначе
🔥34😁5🤡2🌚1
#prog #rust #rustreleasenotes
Вышла версия Rust 1.67.0! В этот раз заметных изменений не так уж и много. Вот полный список, если что. Как всегда, выпишу только то, что интересно мне.
▪️До стейбла докатилось изменение, о котором я уже писал:
▪️Ещё одно такое изменение: замена реализации MPSC-канала из std.
▪️И ещё одно такого рода: порядок дропа временных значений в цепочках из выражений, соединённых только
▪️И ещё одно:
▪️Трейт Sized стал коиндуктивным. Иными словами, если задача доказать ограничение
Остальное в подробных заметках о релизе.
Вышла версия Rust 1.67.0! В этот раз заметных изменений не так уж и много. Вот полный список, если что. Как всегда, выпишу только то, что интересно мне.
▪️До стейбла докатилось изменение, о котором я уже писал:
#[must_use]
на асинхроных функциях теперь предупреждает не только о неиспользуемой футуре, возвращаемой функцией, но и о неиспользуемом возвращённом этой футурой значении.▪️Ещё одно такое изменение: замена реализации MPSC-канала из std.
▪️И ещё одно такого рода: порядок дропа временных значений в цепочках из выражений, соединённых только
&&
и соединённых только ||
, теперь всегда слева направо, без специального отношения к первому подвыражению.▪️И ещё одно:
NonZero*::BITS
.▪️Трейт Sized стал коиндуктивным. Иными словами, если задача доказать ограничение
T: Sized
приводит к необходимости доказать это же самое ограничение, образуя цикл в логике, то вместо ошибки компилятор теперь выводит, что тип таки реализует Sized
. На практике это означает, что рекурсивные типы, параметризованные типом индирекции, теперь нормально компилируются. Скажем, этот код не компилировался до этого изменения и компилируется после:trait Allocator {▪️Компилятор слегка поумнел в плане вывода типов для замыканий.
type Allocated<T>;
}
enum LinkedList<A: Allocator> {
Head,
Next(A::Allocated<Self>),
}
Остальное в подробных заметках о релизе.
blog.rust-lang.org
Announcing Rust 1.67.0 | Rust Blog
Empowering everyone to build reliable and efficient software.
👍11
Forwarded from я что-то �� и всё ����
Оказывается, пайдантик может молча дропнуть создание класса, если немного накосячить с объявлением
Узнала я об этом при попытке проверить работу алиасов. Если базовая модель объявляет поле, а наследник переобъявит его через присваиваение pydantic.Field(alias=...), но *не* укажет тайпхинт, пайдантик дропнет вообще весь класс, как будто его и не было никогда
Причём достаточно одного такого поля, чтобы весь класс улетел в мусорку
Узнала я об этом при попытке проверить работу алиасов. Если базовая модель объявляет поле, а наследник переобъявит его через присваиваение pydantic.Field(alias=...), но *не* укажет тайпхинт, пайдантик дропнет вообще весь класс, как будто его и не было никогда
Причём достаточно одного такого поля, чтобы весь класс улетел в мусорку
🤣13👍4👎3😁1
Не плачь, ибо плачут только четырнадцатилетние девочки.
Ты взрослый мужчина — рыдай!
Ты взрослый мужчина — рыдай!
👍13🤮5😭5🔥1😐1
я что-то �� и всё ����
Оказывается, пайдантик может молча дропнуть создание класса, если немного накосячить с объявлением Узнала я об этом при попытке проверить работу алиасов. Если базовая модель объявляет поле, а наследник переобъявит его через присваиваение pydantic.Field(alias=...)…
Telegram
; pub Mo struct
Окей, пайдантик не виноват. Это пайчарм с непонятного перепугу начал молча проглатывать брошенное RuntimeError
🤣9🤔1
Forwarded from я что-то �� и всё ����
В вывеске часы работы указаны так
Зима: 8:00-21:00
Лето: 8:00-22:00
Теперь загадка жака фреско: как эта аптека работает весной и осенью? :blobcatgooglyholdingitsheadinitshands:
Зима: 8:00-21:00
Лето: 8:00-22:00
Теперь загадка жака фреско: как эта аптека работает весной и осенью? :blobcatgooglyholdingitsheadinitshands:
#prog #c #cpp #моё
Если вам вдруг понадобилось в рантайме выяснить, была ли ваша программа скомпилирована в режиме C или же C++, то вот непотокобезопасная функция, которая вернёт ответ в виде ноль-терминированной строки напрямую на большинстве систем:
...
Нет, всё-таки, как это действительно работает?
Первая строка объявляет переменную
Строковые литералы в C и C++ являются массивами
Что же касается второй строки... Что ж, тут надо разбираться.
Во-первых,
Во-вторых, в этой строчке
литерал символа имеет тип
Тут возникает вопрос, какой же размер у
Итак,
В-третьих, малоизвестный факт заключается в том, что в C и C++ в литерал символа можно записать больше одного символа, и называется это multi-character character literal. То, как именно эти литералы отображаются на численные значения, зависит от реализации — но нам это и не важно, потому что эти значения мы всё равно не используем. А вот что важно — так это то, что и в C, и в C++ такие литералы имеют тип
С учётом изложенного выше, а также того, что оператор деления и в C, и в C++ является левоассоциативным, можно подсчитать, какие же получаются индексы в функции. Для C это
5/4 - 4/2/4 = 1 - 2/4 = 1
, поэтому присваивание записывает конец строки аккурат после первого символа
5/1 - 4/2/1 = 5 - 2/1 = 3
, потому присваивание записывает ноль после второго
В третьей строке строка возвращается, и из-за объявленного типа массив деградирует до указателя на его первый элемент. Признаком конца строки в C является ноль-символ, поэтому все функции стандартной библиотеки считают возвращаемое значение строкой
Если вам вдруг понадобилось в рантайме выяснить, была ли ваша программа скомпилирована в режиме C или же C++, то вот непотокобезопасная функция, которая вернёт ответ в виде ноль-терминированной строки напрямую на большинстве систем:
Как же это работает? В отдельной переменной записывается строка, в нужную позицию записывается признак конца строки, а затем строка возвращается. Всем пока.
char const* get_language() {
static char s[] = "C++\?";
s[sizeof s/sizeof'C'-sizeof'++'/2/sizeof'\?']=0;
return s;
}
...
Нет, всё-таки, как это действительно работает?
Первая строка объявляет переменную
s
и присваивает ей значение. Переменная s
статическая, чтобы возвращаемый указатель не становился висячим сразу после возврата из функции.Строковые литералы в C и C++ являются массивами
char
-ов, включающими в себя неявно добавляемый на фазе трансляции терминирующий нуль-символ. s
объявлена, как переменная типа char[]
. Обычно тип в C(++) нужно выписывать целиком, но длину массива в объявлении переменной можно опустить, если её можно вывести из типа инициализирующего выражения — как в этом случае. Строка "C++\?"
имеет четыре символа (четыре, потому что \?
является escape-ом для ?
(потому что триграфы)), поэтому с учётом конечного нуля получаем, что s
имеет тип char[5]
.Что же касается второй строки... Что ж, тут надо разбираться.
Во-первых,
sizeof
является унарным оператором и, вообще говоря, не требует скобок. При этом у него приоритет выше, чем у арифметических выражений, поэтому в выражении ниже они и не требуются. Не то чтобы это было сильно важно для понимания, но не все об этом знают.Во-вторых, в этой строчке
sizeof
применяется к, в частности, литералу символа. Чему равно значение этого выражения? Казалось, это должно быть 1, поскольку стандарт C прямо диктует (а стандарт C++ вторит), что sizeof(char)
равен 1. Но! Тут мы применяем sizeof
к литералу символа, и тут кроется одно из отличий между C и C++, делающее эту функцию возможной:литерал символа имеет тип
int
в C и тип char
в C++.Тут возникает вопрос, какой же размер у
int
. Если вы программируете не под микроконтроллеры, то на вашей целевой системе тип int
наверняка имеет размер 4 байта. Строго говоря, это не всегда верно, поскольку размер int
является implementation defined, но это настолько распространённое и работающее на практике заблуждение, что после появления 64-битных систем размер int
остался на них 4 байта. Не смотря на то, что int
по замыслу является целым числом нативного для машины размера, смена размера int
на 64-битных платформах до 8 байт сломала бы слишком много программ.Итак,
sizeof'C'
и sizeof'\?'
возвращает 4 для C и 1 для C++. sizeof s
возвращают размер типа s
. Для массива это размер в байтах. Так как s
имеет тип char[5]
, sizeof s
возвращает 5. Но вот что такое sizeof'++'
? Нет, это не опечатка.В-третьих, малоизвестный факт заключается в том, что в C и C++ в литерал символа можно записать больше одного символа, и называется это multi-character character literal. То, как именно эти литералы отображаются на численные значения, зависит от реализации — но нам это и не важно, потому что эти значения мы всё равно не используем. А вот что важно — так это то, что и в C, и в C++ такие литералы имеют тип
int
. Так что sizeof'++'
возвращает таки 4.С учётом изложенного выше, а также того, что оператор деления и в C, и в C++ является левоассоциативным, можно подсчитать, какие же получаются индексы в функции. Для C это
5/4 - 4/2/4 = 1 - 2/4 = 1
, поэтому присваивание записывает конец строки аккурат после первого символа
C
. Для C++ же5/1 - 4/2/1 = 5 - 2/1 = 3
, потому присваивание записывает ноль после второго
+
.В третьей строке строка возвращается, и из-за объявленного типа массив деградирует до указателя на его первый элемент. Признаком конца строки в C является ноль-символ, поэтому все функции стандартной библиотеки считают возвращаемое значение строкой
"C"
в C и "C++"
в C++ соответственно. Как видите, всё очень просто.godbolt.org
Compiler Explorer
Compiler Explorer is an interactive online compiler which shows the assembly output of compiled C++, Rust, Go (and many more) code.
👍16🤯11🔥1
Ну и напоследок о том, как можно эту функцию улучшить. В C++, в отличие от C, поддержка multi-character character literal является необязательной, поэтому конформная реализация C++ может попросту не скомпилировать эту функцию. Для того, чтобы улучшить переносимость между языками, можно убрать этот литерал и заменить
sizeof'++'/2
на (sizeof'+'+sizeof'+')
.👍3