Введение в программирование на rust
Содержание:
- Одежда
- Основание каменной стены
- Акт номер 0, Вступление
- Хорошая документация с актуальными примерами
- Компоненты
- Таблица рейдерства RUST: Расчёт количества взрывчатки
- Акт номер 0x00000000: Память
- Эпилог
- Электричество
- Выделение большего количества виртуальной памяти для Rust
- Перечисление типов
- Характеристики растения
- Бесплатные абстракции
- Обобщенные типы
- Завершающие слова
Одежда
Movember-усыАнтирадиационный костюмБалаклаваБаллон с воздухомБанданаБорода СантыБотинкиБронированный костюмБроня из дорожных знаковВодолазкаВязаная шапочкаГидрокостюмДеревянные щиткиДеревянный нагрудникДеревянный шлемЖелезная маскаЖилет из шкурыЗимняя курткаКартонные Movember усыКепкаКилт из дорожных знаковКожаные перчаткиКомбинезонКонная броня из дереваКонная броня из дорожных знаковКостюм «Ниндзя»Костюм кроликаКостюм мумииКостюм призракаКостюм ученогоКостюм хирургаКостюм чучелаКостюм-бочкаКостяная броняКостяной шлемКроличьи ушкиКурткаЛасты для дайвингаМайкаМаска быкаМаска драконаМаска крысыМеталлический нагрудникНагрудная повязкаНаушникиОбувь из мешковиныОбычные подковыОдежда бандита-охранникаОленьи рогаОчки ночного виденияПанамаПерчатки из дорожных знаковПерчатки из мешковиныПовязка из мешковиныПовязка чучелаПодводная маскаПодковы высокого качестваПончоПраздничный колпакПротивогазРубашкаРубашка из мешковиныСапоги из шкурыСапоги-лягушкиСветящиеся глазаСедельная сумкаСедло для лошадиСиний комбинезонСолнцезащитные очкиТактические перчаткиТолстовка с капюшономТяжелые пуленепробиваемые поножиТяжелый латный нагрудникТяжелый пуленепробиваемый шлемФиолетовые солнцезащитные очкиФуражка шахтераФутболкаШапка СантыШапка из волкаШапка кроликаШлем ClatterШлем бунтаряШлем из ведраШлем из кофейной банкиШляпа со свечойШляпа-гнездоШортыШтаныШтаны из мешковиныШтаны из шкурыЮбка из кожыЯщик-костюм
Основание каменной стены
Теперь, когда вы создали все необходимое и укрепили свою базу, пришло время подумать об улучшении прочности вашей базы путем создания каменных стен.
Это отличный шаг к обеспечению долговечности вашей базы, поскольку камень в три раза более устойчив к взрывчатым веществам, чем ваши укрепленные деревянные стены.
Ваши каменные стены получат десять зарядов взрывчатки от противников, чтобы снести ваши стены, в отличие от трех зарядов, необходимых для разрушения укрепленных деревянных стен.
Чтобы обеспечить полное обновление полностью усиленной базы, вам нужно собрать одну тысячу шестьсот камней.
Используйте свой топор и метод подбора, чтобы найти свободный камень, чтобы собрать достаточно для вашего подкрепления.
Собрав весь необходимый камень, улучшите все компоненты своей базы.
Улучшите свой фундамент, три построенные вами укрепленные деревянные стены, деревянный дверной проем и фундаментный потолок, построенный вами ранее.
Акт номер 0, Вступление
Ок. Мне довелось обучать программистов вот уже как 10 лет. Я видел разный народ. Кто-то приходил ко мне с вопросами о том, как компилятор оптимизирует код с поддержкой MMX в процессоре, а кто-то спрашивал, можно ли скомпилировать код на Java в С#. Разница между первыми и вторыми – это понимание того как работает процессор.
В этот момент большинство из тех кто учился программировать по ютубу просматривая видео из серии «Как скачать генератор to-do list на node.js, React, brew, JSX, Pug, LESS за 10 секунд» начинают убегать. Не бойтесь. Я попытаюсь всё объяснить по-человечески. Конечно, есть на хабре и те, кто могут открыть бинарный файл в HEX, посмотреть на 7а 45 4с 46 01 01 01 00 и сказать: «Да этож линуксовский бинарник!» Таким не обязательно читать дальше.
Хорошая документация с актуальными примерами
Стандартная библиотека Rust очень хорошо документирована. Html-документация генерируется автоматически по исходному коду с markdown-описаниями в док-комментариях. Более того, док-комментарии в коде на Rust содержат примеры кода, которые исполняются во время запуска тестов. Этим гарантируется актуальность примеров:
Здесь пример использования метода у типа
будет выполнен как тест во время запуска тестов.
Кроме этого, для Rust-библиотек распространена практика создания примеров их использования в виде небольших самостоятельных программ, расположенных в директории в корне проекта
Эти примеры также являются важной частью документации и они также компилируются и выполняются во время прогона тестов, но их можно запускать и независимо от тестов
Компоненты
БрезентБронированный модульБронированный пассажирский модульВеревкаДорожные знакиКабина с двигателемКарбюратор высокого качестваКарбюратор низкого качестваКарбюратор среднего качестваКлапаны высокого качестваКлапаны низкого качестваКлапаны среднего качестваКлейКоленчатый вал высокого качестваКоленчатый вал низкого качестваКоленчатый вал среднего качестваКорпус винтовкиКорпус пистолет-пулеметаКорпус полуавтоматаЛистовой металлМеталлическая пружинаМеталлическая трубаМеталлическое лезвиеМодуль двигателя автомобиляМодуль двигателя транспортаМодуль для Большого ГрузовикаМодуль задних сиденийМодуль кабины транспортаМодуль таксиНабор для шитьяОтбеливательПалочкиПассажирский модульПоршни высокого качестваПоршни низкого качестваПоршни среднего качестваПропановый баллонСвеча зажигания высокого качестваСвеча зажигания низкого качестваСвеча зажигания среднего качестваСкотчСтарые микросхемыТопливный бакШестерниЭлектрический предохранитель
Таблица рейдерства RUST: Расчёт количества взрывчатки
Доброго времени суток, Дорогие Друзья! Мы представляем Вам гайд «Таблица рейдерства RUST: Расчёт количества взрывчатки». И если Вы еще не ознакомились с предыдущими гайдами — мы рекомендуем Вам наверстать упущенное, чтобы Вам было понятно о чем сегодня пойдет речь. Мы надеемся, что этот гайд Вам будет полезен!
Бобовая граната:
Шкаф — 3 | Сера — 360Автоматическая турель — 16 | Сера — 1,920Огненная турель — 7 | Сера — 840Ловушка из дробовика — 7 | Сера — 840Металлическая витрина магазина — 84 | Сера — 10,080Люк — 18 | Сера — 2,160Решётчатый настил — 18 | Сера — 2,160
Бобовая сишка:
Шкаф — 1 | Сера — 480Автоматическая турель — 2 | Сера — 960Огненная турель — 1 | Сера — 480Ловушка из дробовика — 1 | Сера — 480Металлическая витрина магазина — 18 | Сера — 8,640Люк — 4 | Сера — 1,920Решётчатый настил — 4 | Сера — 1,920
Разрывные патроны (самый выгодный рейд):
Шкаф — 9 | Сера — 225Автоматическая турель — 100 | Сера — 2,500Огненная турель — 30 | Сера — 750Ловушка из дробовика — 30 | Сера — 750Металлическая витрина магазина — 300 | Сера — 7,500Люк — 63 | Сера — 1,575Решётчатый настил — 63 | Сера — 1,575
Шкаф — 1 | Сера — 2,200Автоматическая турель — 1 | Сера — 2,200Огненная турель — 1 | Сера — 2,200Ловушка из дробовика — 1 | Сера — 2,200Металлическая витрина магазина — 3 | Сера — 6,600Люк — 1 | Сера — 2,200Решётчатый настил — 1 | Сера — 2,200
Ракета:
Шкаф — 1 | Сера — 1,400Автоматическая турель — 4 | Сера — 5,600Огненная турель — 2 | Сера — 2,800Ловушка из дробовика — 2 | Сера — 2,800Металлическая витрина магазина — 6 | Сера — 8,400Люк — 2 | Сера — 2,800Решётчатый настил — 2 | Сера — 2,800
Скоростная ракета:
Шкаф — 1 | Сера — 420Автоматическая турель — 10 | Сера — 4,200Огненная турель — 4 | Сера — 1,680Ловушка из дробовика — 4 | Сера — 1,680Металлическая витрина магазина — 22 | Сера — 9,240Люк — 5 | Сера — 2,100Решётчатый настил — 5 | Сера — 2,100
40mm Граната:
Шкаф — 1Автоматическая турель — 12Огненная турель — 6Ловушка из дробовика — 6Металлическая витрина магазина — 30Люк — 7Решётчатый настил — 7
Огнемёт:
Деревянная стена | Топливо — ×196Деревянная дверь | Топливо — ×84Высокая внешняя деревянная стена | Топливо — ×392Деревянная оконная решётка | Топливо — ×196
Шкаф | Топливо — ×42Автоматическая турель | Топливо — ×392
Огненная стрела:
Деревянная стена — 25 стрелДеревянная дверь — 50 стрелВысокая внешняя деревянная стена — 250 стрелДеревянная оконная решётка — 125 стрел
Шкаф — 25 стрелАвтоматическая турель — 125 стрелОгненная турель — 75 стрелЛовушка из дробовика — 75 стрел
Каменный патрон:
Деревянная стена — ×93Каменная стена — ×556
Деревянная дверь — ×45
Высокая внешняя деревянная стена — ×186Высокая внешняя каменная стена — ×556
Деревянная оконная решётка — ×93
Шкаф — ×23Автоматическая турель — ×56Огненная турель — ×17Ловушка из дробовика — ×17
Бобовая граната — 191 | Сера — 22,920Бобовая сишка (сачель) — 20 | Сера — 9,600Разрывные патроны — 571 | Сера — 14,275С4 — 3 | Сера — 6,600Ракета — 11| Сера — 15,400Скоростная ракета — 7 | Сера — 1,400
А на этом все, Дорогие Друзья. Мы надеемся, что гайд «Таблица рейдерства RUST: Расчёт количества взрывчатки» был полезен для Вас. Ищите больше гайдов по всем играм на нашем сайте!Удачных Вам рейдов, и приятной Вам игры!
Акт номер 0x00000000: Память
Хорошо, мы видели историю того, как изменялся подход к написанию программ и почему он изменялся. Единственный момент, на который мы не смотрели – это память. Этот момент является очень важным.
В древности ваша программа (в большинстве случаев) запускалась на процессоре как полновластный владелец всей системы. Вы могли обратиться к любому участку памяти, писать и читать из этого участка памяти и делать что вздумается. Этот подход был прост и ужасен. Вы могли в любой момент изменить память, которой пользовалась другая программа на компьютере. Решили сохранить в памяти огромную картинку с разрешением 320х240? Упс! Неправильно прописанный указатель переписывает содержание функций операционной системы, и вместо красивого изображения вы получаете полное зависание системы (если повезёт, если не повезёт, можно заодно и диск отформатировать).
Вирусы в те стародавние времена писались только так. Почему бы не перехватить функцию в DOS, которая пишет данные на диск? Да проще простого! Перехватывай. Диски стирались, криптовались и чего только не делались. Делов-то.
Со временем разработчики процессоров начали бороться с этим кошмаром путём усложнения модели работы с памятью. С 1985х в процессоры начали встраивать новый «защищённый режим» работы с памятью. Вместо того чтобы позволять каждой программе работать с памятью напрямую, программе предоставлялся интерфейс, для того чтобы запросить виртуальную память и работать с этой памятью. Память была виртуальной, потому что эта память не гарантировала выдачу вам блоков RAM с шестой по девятый. Вы просили систему дать вам полкило памяти, вы её получали. Когда ваша программа писала в эти полкило памяти, операционная система уже разбиралась что с этой памятью делать. В какой конкретно чип в RAM эти ваши данные положить. А если вы этими данными не пользовались, то система могла их и сбросить в Swap.
Самое главное, ваша программа получала свой виртуальный адрес, а система гарантировала, что никакая другая программа в этот кусок памяти писать не будет. В том числе система гарантировала, что другие программы в вашу память писать не будут. Всё работало просто замечательно:
Вся эта беготня с памятью создала необходимость управления этой памятью. Ваша программа на C должна получить память, обращаясь к операционной системе. Система вам эту память выдаст. А может и не выдать. Результат зависит, но скорее всего, будет такой вот:
После того как вы эту память получили вам нужно её «инициализировать», то бишь записать туда начальные значения переменных, которые вам нужны. Иначе вы могли получить кусок памяти, в которой валялся какой-то мусор.
А теперь самое прикольное – каждый раз, когда вы попросили у системы память, эта память будет оставаться вашей, пока не будет сделано одно из двух: либо вы эту память отдадите системе обратно, либо вы завершите программу, и тогда вся ваша память освободится.
Что же, это просто, так ведь? Если попросили полкило памяти, то и отдайте полкило памяти. Делов-то. А что если вы попросили полкило памяти и отдаёте её обратно кусками по 10 килобайт? И вот, 2 куска в самом конце не отдали (забыли, поставили неправильный знак сравнения в цикле и последние два куска остались за вами). А потом вы попросили ещё полкило, то есть теперь ваша программа занимает 520 килобайт. И опять отдаёте её кусками и 2 куска не отдали? Теперь у нас 40 лишних килобайт. Результат:
Такая штука называется утечкой памяти. И, в результате, вы сидите в 4 утра с красными глазами перед отладчиком и орёте благим матом «Ну где эта с_ка течёт?»
А ещё есть один прекрасный трюк, как насчёт того, чтобы попросить память у системы, а потом удалить указатель на эту память? В таком случае вы эту память и вернуть обратно не сможете. Результат?
А ещё можно обратиться к памяти по адресу 0x00000000 (нулевой адрес). Результат?
А ещё можно…
Короче вы поняли. Работа с памятью требует тщательного планирования и правильного управления. Любой программист на С и С++ обязательно проверит каждую функцию запроса памяти и убедится в том, что ничего нигде не течёт. Чем сложнее становится проект, тем сложнее эту память проверять. Появляются другие инструменты проверки. Например, знакомая каждому хабровчанину PVS-Studio. Статический анализатор, который может половить баги памяти в вашей программе.
Программист, помни, работа с памятью – это очень тяжёлая ответственность. Ладно. Это всё решили в Яве и Дотнете.
Эпилог
Всегда хотелось такую игру, в которой была бы возможность выживать, созидать или разрушать, помогать или вредить, находить или терять, сеять добро или порождать зло, объединяться, воевать, торговать, исследовать, наблюдать как день сменяет ночь или как облака плывут по голубому небу или как колышется трава… проще говоря, жить.
Эпилог раст
Rust — та самая игра и даже больше! Это невероятно глубокая и умная игра, причем, достигающая всего этого за счет социума! Именно реальные игроки, злые и не очень, люди, своими действиями доводят игру до невероятного уровня проработки! Взять хотя бы те же партизанские войны, когда игроки выдумывают всевозможные способы насолить врагу и, например, закрывают частоколом главный вход в дом. Искусственный интеллект вряд ли бы сам додумался до этого.
Ни в какой игре ранее мы не испытывали такого удовольствия от награбленного или страха от нападений грабителей, или удовлетворения после постройки сорокового этажа вашего нового пентхауса, или … а, да что тут рассказывать, поиграйте и сами все испытайте! Можно бесконечно перечислять все естественные и искусственные возможности игры.
Учитывая, что игра пока ещё на ранней стадии разработки, становится одновременно радостно и страшно от того, что предстоит испытать в будущем в игре. А мне очень приятно писать обзор для такой действительно классной игры Rust!
Итоговый балл в конце нашего обзора Rust с учетом пережитых впечатлений и не смотря на некоторые недочеты 9 баллов! Авансом. Спасибо вам, Гарри!
Электричество
HBHF-датчикRAND-переключательTest GeneratorАвтоматическая турельБлокаторБольшая анимированная неоновая табличкаБольшая солнечная панельБольшой аккумуляторВетрогенераторВодяной насосВоспламенительГофра для кабеляЖидкостный разделительЗвуковая сигнализацияКатушка ТеслаКнопкаКомбинатор питанияКомпьютерная станцияКонтроллер двериЛазерный датчикЛифтМаленький аккумуляторМалый генераторМигалкаНажимная плитаНеоновая табличка (большая)Неоновая табличка (маленькая)Неоновая табличка (средняя)ПейджерПереключательПереключатель «И»Переключатель «ИЛИ»Переключатель «Исключающее ИЛИ»Подъемник для транспортаПоисковый фонарьПотолочный светильникПроводПростая лампаРадиопередатчикРадиоприемникРазбрызгиватель РазветвительРоскошная Рождественская гирляндаСиренаСоединитель жидкостиСредний аккумуляторСредняя анимированная табличкаСчетчикСчетчик ресурсовТаймерТренировочная мишеньУмная СигнализацияУмный переключательЦиркуляционный насосШлангЭлектрический обогревательЭлектрический разветвительЭлектроочиститель водыЯчейка памяти
Выделение большего количества виртуальной памяти для Rust
Откройте панель управления, выполнив поиск в строке поиска Windows и щелкнув приложение. Щелкните «Системы и безопасность». Снова нажмите «Системы», и откроется другое окно.
Справа после открытия «Системы» вы увидите «Расширенные настройки системы» под соответствующими настройками. Щелкните по нему, и откроется другое окно. Перейдите на вкладку «Дополнительно» и нажмите «Настройки ..» в разделе производительности.
Снимите флажок «Автоматически управлять размером файла подкачки для всех дисков». Выберите диск, на котором установлен Rust, и используйте под ним нестандартный размер.
Есть два входа для нестандартного размера: начальный и максимальный размер. Для исходного размера просто скопируйте рекомендуемый размер, указанный в разделе «Общий размер файла подкачки для всех дисков».
Это отличается для компьютеров с разной оперативной памятью, поэтому не копируйте числа на картинке выше, а просто используйте то, что показано в вашем окне.
Для максимального размера вам необходимо вычислить точный размер. Он рассчитывается путем умножения текущего выделенного размера файла подкачки на 1,5. В приведенном выше примере показано, что в настоящее время выделено 14848 МБ.
Если вы умножите это на 1,5, вы получите 24576. Это число, которое вам нужно вычислить для себя, и ввести это число для максимального размера. Нажмите «ОК», и это должно максимально увеличить объем доступной на вашем компьютере памяти.
Перечисление типов
В Rust есть тип-перечисление , который в отличии от перечислений в других языках, является перечислением не константных значений одного типа, а перечислением разных типов, которые может принимать значение. Это — алгебраический тип данных (АТД), простой и выразительный инструмент для конструирования высокоуровневых абстракций.
Хороший пример АТД — это тип библиотеки , который представляет любое корректное JSON-значение:
АТД во многих случаях избавляет программиста от написания низкоуровневого кода для проверки целостности и непротиворечивости типов данных. Что актуально не только для языков с динамической типизацией, но и для статически типизированных языков.
Вообще, в Rust используется чуть менее, чем везде — и это прекрасно! Потому что АТД — это абстракция очень высокого уровня, сравнимая с наследованием классов и полиморфизмом подтипов в ООП. Выражение традиционно низкоуровневых концепций в терминах АТД неожиданно делает их не такими уж и низкоуровневыми.
Классический пример — это реализация отсутствующего значения. Во многих языках прошлого поколения в качестве отсутствующего зачения используется . И это очень плохо, потому что — это и тип, и значение, которое к тому же могут принимать переменные совершенно разных типов. Один от другого не отличим и мы всегда должны иметь в виду, что наш объект может оказаться в любом месте програмы вне зависимости от его типа и от того, вообще требуется ли для данного типа иметь отсутствующее значение (конечно это касается только ссылочных типов, которые используются в популярных ныне высокоуровневых языках неявно).
Вот как решается проблема реализации отсутствующего значения в Rust:
С таким подходом можно убрать из безопасной части языка совсем. Концептуально и просто, теперь сам опционален и вписан в существующую систему типов как абстракция более высокого уровня, равно применимая к любым типам, не только к ссылочным. «Под капотом», в реализации, ссылочные типы все равно имеют , поэтому для таких типов использование не влечет накладных расходов: представляется как и дополнительного места для хранения дискриминанта не требуется. Так что и для низкоуровневых системных задач применим.
Подробнее об АТД и преимуществах их использования, вы можете прочитать в статье Романа Душкина «Алгебраические типы данных и их использование в программировании».
Характеристики растения
Само растение обладает собственными характеристиками.
- Здоровье – следите за тем, чтобы оно было ближе к 100%. Примечательно, что у только что посаженного растения здоровье будет постепенно пополняться, так что не паникуйте раньше времени.
- Возраст – позволяет вам по времени засекать стадии роста растения, что позволит вам быстрее «въехать» в тему выращивания.
- Стадия – это стадии роста растения. Проценты рядом показывают, когда завершится текущая стадия роста. Как мы уже сказали выше, в Rust наблюдается 8 стадий роста растений, от посадки и до «смерти».
- Потребление воды – сколько воды требуется растению на той или иной стадии.
- Урожайность – сколько вы можете получить ресурсов с растения.
Бесплатные абстракции
Удивительно, насколько наличие абстракций с нулевой стоимостью, даже самых элементарных, упрощает прикладную разработку. Посмотрите на следующий код, который написан на языке, считающимся высокоуровневым:
И сравните с тем, как то же самое поведение реализуется в Rust:
Где вам понятнее, что происходит и где, по-вашему, вероятность ошибиться меньше? Мне кажется, что ответ очевиден.
Помимо демонстрации отличного дизайна стандартной библиотеки, этот пример показывает, насколько Rust может быть удобен для высокоуровневого программирования: вместо того, чтобы принимать в свои функции непонятные числа, вы можете использовать собственные типы, созданные под конкретную задачу, и это без дополнительных накладных расходов. (Правда, в случае структуры с несколькими полями, как у , по-умолчанию будет производиться выравнивание, но это поведение можно менять с помощью атрибута .)
Числовой тип — это «низкоуровневый» тип, потому что он отвечает на вопрос как значение будет представлено в памяти, а не на вопрос что оно собой представляет в контексте задачи. Но в Rust можно очень легко и элегантно вводить новые типы поверх существующих:
Несмотря на то, что оба значения и имеют одинаковое числовое представление, они являются объектами разных типов, и поэтому перепутать и подставить одно значение вместо другого не получится. Этот паттерн называется «Новый тип» (New type), и он совершенно бесплатен в использовании. (Подробнее о преимуществах использования паттерна «Новый тип» вы можете прочитать в замечательной статье Передача намерений.)
«Новый тип», так же как и вообще любая пользовательская структура или перечисление в Rust, может выступать границей раздела нескольких уровней программирования. И чтобы пользователь мог переходить эту границу всегда, когда это удобно для решения его задачи, эти абстракции не должны сами по себе требовать сколь-либо значимых дополнительных расходов. Иначе пользователь будет вынужден чаще пользоваться имеющимися низкоуровневыми типами, вместо того, чтобы создавать на их основе свои, высокоуровневые.
Обобщенные типы
Помимо того, что обобщенные типы избавляют от написания шаблонного кода, они являются отличным инструментом абстрагирования и высокоуровневой спецификации поведения. Вот что я имею в виду:
Тут уже сразу по сигнатуре функции понятно, что мы можем принять в аргументах объекты одного и того же типа , для которого реализовано отношение частичного порядка. Таким образом, от указания конкретного типа, мы переходим к указанию неких характеристик используемого типа с помощью типажей (traits), которые могут быть присущи самым разным типам. Можно указывать и достаточно нетривиальные зависимости между типами. Однако сами по себе характеристики, ровно как и соответствующие им типажи, могут быть как высокоуровневыми, так и низкоуровневыми. То есть они могут характеризовать тип как со стороны требований решаемой задачи, так и со стороны требований реализации. Вот небольшой пример из стандартной библиотеки:
Метод хеш-таблицы, хранящей значения типа , соответствующие ключам типа , принимает ссылку некоторого типа , которую также можно получить из ссылки на ключ (это правило задано отношением ). Что это значит? Это значит, что для случая, например, строковых ключей () вместо того, чтобы всякий раз передавать в ссылку на владеющую строку (), вы можете, скажем, передавать строковый срез (), к которому можно привести ссылку на владеющую строку с помощью операции . Это позволяет избежать лишних аллокаций и просто повышает удобство использования: вызывающий код не должен думать, какую именно строку передавать — метод корректно сработает для обоих вариантов.
Выглядит как что-то низкоуровневое. Но такое поведение часто реализует определенное требование самой задачи. Например, у нас есть тип с приватным конструктором:
Можно сделать так, что будет возможно сконструировать только с помощью некоего сервиса, который либо выдает новое число из глобальной последовательности идентификаторов, либо десериализует значение из ранее сконструированного и сохраненного. (Подробнее о преимуществах подобного подхода к проектированию типов вы можете прочитать в статье Парсите, а не валидируйте.)
Теперь мы хотим использовать как ключ в хеш-таблице, и это хорошо, так как у нас в таком случае появляется гарантия, что значение когда-то было корректно сконструировано и добавлено в таблицу, других вариантов его получить нет. Но мы должны иметь возможность обращаться к значению также и по ключу типа ! Потому что принятое число, например от пользователя, может оказаться верным значением идентификатора, а может и нет, и мы не хотим всякий раз делать сложную проверку его корректности, нам достаточно того, можем мы получить значение из хеш-таблицы по этому ключу, или не можем. Такое поведение легко осуществить, если мы реализуем соответствующий :
Вернемся к определению метода . Для типа там представлено также одно весьма низкоуровневое ограничение — . Оно говорит о том, что тип не обязательно должен быть типом с известным размером на этапе компиляции (что задано по умолчанию для обобщенных типов). Так как в метод передается только ссылка на этот тип, сам тип может быть и типом с неизвестным размером. Размеры типов принимаемых и возвращаемых значений у функций всегда должны быть известны на этапе компиляции, иначе будет невозможно зарезервировать для них место на стеке.
Итак, на границе высокоуровневого и низкоуровневого кода, проходящей через определения обобщенных типов, мы можем столкнуться как с высокоуровневыми, так и с низкоуровневыми ограничениями, причем далеко не всегда просто отделить одни от других. Но помочь с этим может введение новых типажей:
Теперь можно вместо набора из трех ограничений писать только одно, которое автоматически будет выполняться для всякого типа, имеющего исходные три характеристики. Таким образом можно скрыть множество низкоуровневых требований за одним высокоуровневым.
Завершающие слова
Надеюсь, что данная быстрая демонстрация убедила вас в мощи, предоставляемой типизированным перемещением, совмещенной с фантомными типами. Это замечательный инструмент для обеспечения безопасности вашего кода. Он используется во многих местах в стандартной библиотеке Rust и во многих хорошо продуманных сторонних библиотеках.
Сейчас я не знаю другого ЯП, который бы предоставлял семантику типизированных перемещений (отмечу, C++ имеет нетипизированную семантику перемещения), думаю, что другие языки в конечном итоге включат такой же механизм, если он будет востребован. К слову, я не могу без него обойтись 🙂