Я просматривал код некоторых основных типов в Rust, например приятно простая реализация Option<T> или странной магии макросов позади tuple, и я смог найти все нужные мне типы в libcore. Все, кроме одного - bool. Я тоже нигде не нашел.

Где находится код bool в Rust? Я знаю, что это не самый новый тип, но я был удивлен, что не смог его найти.

Благодаря ответам Фрэнсиса и Родриго я заметил, что код, который я нашел для других примитивов, был просто их особенностями и соответствующими макросами, но не реальными реализациями.

В книге Rust утверждается, что примитивы встроены в язык, но меня это объяснение не устраивает. Когда они были построены? Можно ли это проследить до того времени, когда компилятор Rust был впервые построен на Rust, или это произошло, когда он еще был построен на OCaml? Существует ли соответствующий код?

12
ljedrz 5 Сен 2016 в 21:07

3 ответа

Лучший ответ

Итак, вот еще немного информации о том, что происходит в компиляторе. Для начала, как уже упоминалось, фактические операции, которые происходят с логическими значениями, полностью обрабатываются LLVM и напрямую транслируются в соответствующие инструкции ЦП. Хотя есть некоторые случаи, когда код просто волшебным образом появляется из-за начальной загрузки, это не один из них. Компилятор специально написан для обработки этих типов и выдачи правильных инструкций LLVM.

Для самых ранних частей компиляции (например, во время раскрытия макроса) тип bool не является особенным. Это просто некий путь с идентификатором bool. В конечном итоге здесь преобразуется в примитивный тип. Фактическое определение типа находится здесь.

Итак, теперь давайте посмотрим, как работает оператор !. Как я упоминал ранее, код в libcore, который выполняет impl Not for bool, никогда не используется. Код в форме !expr преобразуется в <T as Not>::not(expr) здесь. Однако вы заметите, что он проверяет, действительно ли это конкретное выражение является вызовом метода или нет, и просто оставляет его как !expr, если оно не предназначено для вызова метода. Откуда это знать? Вызов в MIR - это просто поиск в кеше. Кеш был заполнен во время проверки типа. Здесь - где происходит вставка кеша - в основном проверяет, реализована ли черта Not для данного типа каждый раз, когда он видит !. Вы заметите, что эта строка специально исключает логические и целочисленные типы, которые в конечном итоге напрямую компилируются в инструкции LLVM.

Это грубая картина того, как это определяется. Вы найдете аналогичный код в тех же файлах для других примитивов. Теоретически где-то может быть какая-то строка, которая была бы enum bool { true, false } - но в конечном итоге тот же самый код все равно должен был бы переопределить ее и выдать соответствующие встроенные функции LLVM, а целые числа не могли быть представлены таким образом.

14
sgrif 16 Сен 2016 в 20:17

Вы можете увидеть определение для core::i32 только из-за констант i32::MIN и i32::MAX. Фактический тип - это просто псевдоним для встроенного типа i32.

В случае core::f32, например, есть много полезных констант.

Но для bool нет полезных значений, кроме true и false, которые являются ключевыми словами, поэтому нет источника для bool.

3
rodrigo 5 Сен 2016 в 18:56

bool - примитивный тип. Примитивные типы и операции над ними реализуются компилятором, то есть компилятор испускает специализированный код для выполнения операций над примитивными типами.

Вы увидите, что bool реализует множество черт. Эти реализации происходят из libcore, но они часто реализуются с помощью соответствующего оператора. Например, Not::not реализуется путем возврата !self. Для любого непримитивного типа это вызовет Not::not рекурсивно и вызовет переполнение стека, но для примитивных типов компилятор разрешает оператор по-другому, и эти реализации признаков предоставляются только в интересах универсального кода.

11
Francis Gagné 5 Сен 2016 в 18:50