ламидий раст что это

Чего не стоит делать в Rust, если начали играть в 2021 году

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Rust – это необычный симулятор выживания, который привлек к себе внимание огромное количество геймеров. При этом новички часто думают, что в этом проекте нет ничего сложного, и уже с самого начала делают все то, что и в других играх с элементами выживания.

К сожалению, Rust не отличается особым гостеприимством по отношению к новым игрокам, поэтому стартовать бывает довольно сложно. Перед вами подборка главных ошибок, которые делают новички, решившие поиграть в Rust в 2021 году.

Одному будет тяжело

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Rust – далеко не самая лучшая многопользовательская игра для одного человека. Здесь есть несколько этапов развития, и добраться до каждого из них можно только за счет продолжительного гринда. Если играть в команде со своими друзьями, то вы гораздо быстрее достигните цели, чем в одиночку.

Также стоит отметить, что 99% других игроков не дадут вам мирно существовать в виртуальном мире игры. Вам постоянно придется отбиваться от обезумивших «дикарей», которые захотят отобрать ваши вещи и ресурсы. Естественно, ни у одного новичка не получится защитить себя от оравы более опытных игроков, поэтому лучше изначально залетать в Rust хотя бы с парой друзей.

Никому нельзя верить

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Этот пункт частично противоречит предыдущему, но при этом он еще более важен. Прежде всего вам стоит забыть о том, что взаимодействие с другими игроками в многопользовательских проектах – это норма. Rust вообще не та игра, где нужно объединяться с незнакомыми людьми, чтобы вместе получить больше лута или ресурсов. Здесь вы можете рассчитывать только на себя, и если начнете доверять первому встречному игроку, то очень скоро поймете, почему этого нельзя делать. Особенно это касается товарищей с хорошей экипировкой, которых вы встретите на своем пути.

Дело в том, что в Rust каждый играет сам за себя, а опытные игроки очень часто обманывают новичков самыми разными способами. Незнакомец, который предложит побегать с ним по виртуальному миру и при этом будет носить броню заметно лучше вашей, скорей всего грифер. Это такой игрок, который при первой же удобной возможности просто вас убьет и заберет все вещи. Так что, начиная играть в Rust, никому не доверяйте!

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Курс юного строителя

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Если вы вдруг не знали, то в Rust есть строительство, и здесь оно играет довольно важную роль. При этом данная механика имеет ряд особенностей, которые придется изучить в самом начале знакомства с игрой, иначе ваши архитектурные «шедевры» будут попросту разваливаться, а вы впустую потратите ценные ресурсы.

Прежде всего стоит отметить, что у каждого строительного блока есть мягкая и твердая сторона. Во время строительства блок всегда нужно устанавливать таким образом, чтобы твердая сторона находилась снаружи будущего здания. Если не соблюдать это правило и размещать материалы как попало, то вашу постройку сможет развалить первый попавшийся игрок, причем с помощью обычного топора или кирки. Согласитесь, будет не очень приятно наблюдать за тем, как несколько часов ваших трудов кто-то разбирает по кирпичикам за считаные минуты.

Все вещи в одном месте

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Огромное количество игроков в Rust вообще не уделяют время крафту. Они считают, что гораздо проще украсть готовые предметы у других пользователей, чем стоять у станка и пытаться что-то сделать. Именно поэтому в этой игре противопоказано хранить все свои вещи в одном месте.

Ни в коем случае не размещайте абсолютно все запасы на единственной базе, да еще и в конкретном помещении. В таком случае после случайного налета кучки любителей халявы вы потеряете абсолютно все. Конечно, вряд ли у новичка хватит ресурсов, чтобы построить себе 4-5 домов и правильно распределить по ним ценные предметы, но хотя бы попробуйте сделать что-то подобное. Неплохим решением будет на территории одной базы построить несколько «нычек» и распределить по ним ресурсы и предметы.

Не забывайте про аптечки

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Если вы решите, что аптечки вам не нужны и со своим крутым автоматом вы сможете одолеть кого угодно, то Rust очень быстро вас разочарует. Здесь очень просто погибнуть, и иногда вы даже не будете понимать, почему это вообще произошло. В результате игрок, у которого было полно аптечек, просто завалит вас рандомной палкой и заберет тот самый крутой автомат.

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Поставьте себе домофон

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Если же вы не можете сделать кодовый замок или уже поставили везде обычные двери, то не делайте ключ. Пускай доступ к зданию будет только у вас. Отсутствие ключа гарантировано защитит ваши владения, даже если вы внезапно погибнете.

Не используйте факел

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Дело в том, что свет от факела моментально привлечет к вам внимание других игроков. Часть из них будет гриферами, которые быстро прибегут на ваш «сигнал» и просто убьют. На этом ваш многообещающий забег в Rust просто закончится и придется начинать все сначала. Первое время лучше бегайте без факела и пытайтесь ориентироваться на карте с помощью своего зрения.

Вы всегда в опасности

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Многие новички ошибочно думают, что после того, как они построят себе укрытие и обзаведутся хоть какой-то экипировкой, можно просто расслабиться и наслаждаться игровым процессом Rust. Этот проект не об этом, вы всегда будете под прицелом у других игроков! Причем если у вас вдруг все слишком хорошо и на это обратят внимание остальные пользователи игровой сессии, то очень скоро вас ждет набег незваных гостей.

Перестрелка – не самая лучшая идея

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Некоторые новички в Rust почему-то считают, что это экшен-шутер, в котором прямо-таки необходимо ввязываться в перестрелки и каждую минуту показывать, кто здесь круче. На самом деле проект про выживание, и я вам гарантирую, что ваша беготня с автоматом закончится очень быстро, если вы вдруг решите, что можете держать всю карту в страхе.

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Вот такие советы мы решили дать новичкам, которые только надумали залететь в Rust! Делая все эти вещи, вы гарантировано проживете в виртуальном мире игры чуточку дольше и при этом гораздо лучше узнаете все тонкости проекта. Главное, не забывайте всегда быть начеку, здесь нет зоны комфорта.

Источник

Языковое замещение, или Почему Rust сменяет C

Rust — амбициозный проект компании Mozilla, язык программирования, который по задумке создателей должен стать следующей ступенью эволюции C и C++.

В компании Evrone язык Rust применяется на многих проектах, и наши инженеры накопили большую экспертизу в этом направлении. В публикации мы расскажем об особенностях Rust.

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

Работу над Rust начал в 2006 году энтузиаст Грэйдон Хор. В 2009-м проектом заинтересовалась Mozilla, и уже спустя год был дан публичный анонс нового языка программирования.

Альфа-версия Rust появилась в 2012 году. Через год авторы браузерного движка Servo на базе этого языка сообщили, что их детище получило поддержку Samsung. Благодаря этому удалось портировать код движка на ARM-архитектуру.

Версия Rust 1.0 была представлена в мае 2015 года. В том же году язык занял третье место в опросе Stack Overflow о любимых инструментах разработчиков. Начиная с 2016 года Rust регулярно возглавляет этот список.

Данный язык поддерживает основные парадигмы программирования: объектно ориентированное, параллельное, функциональное и процедурное. Rust универсален и подходит для решения различных задач: разработки операционных систем, программ общего назначения, веб-серверов и клиентов, систем мониторинга серверов, разработки инфраструктуры, приложений для мониторинга системы, блокчейн-сетей, игровых и браузерных движков.

Rust создавался в первую очередь как язык системного программирования. Он предоставляет достаточно возможностей для управления памятью и защиты от уязвимостей, чтобы стать востребованным инструментом для разработки операционных систем и ключевых приложений. Главная проблема языка — низкая поддержка со стороны производителей «железа», предпочитающих использовать для работы именно С/С++.

Системы на базе распределенного реестра должны уметь быстро обрабатывать запросы внутри сети при минимальной нагрузке на устройство. Инструментарий С++ отлично справляется с этой задачей (именно на нем работают блокчейны Bitcoin и Ethereum), а посему разработка инфраструктуры с использованием Rust окажется еще эффективнее.

Уже сейчас Rust может использоваться для полноценного создания веб-проектов, инструментарий языка позволяет создать и фронт-энд, и бэк-энд. Клиентская часть реализуется, например, на вдохновленном React и Angular фреймворке Yew. Простая разработка веб-серверов на Rust возможна благодаря actix-web — очень производительному фреймворку, поддерживающему WebSockets, TLS и HTTP/2.0. Также доступны другие инструменты: rocket, conduit, gotham, pencil.

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

С++ почти 40 лет доминировал среди других языков, успел стать промышленным стандартом и по праву удерживает это звание по сей день. Rust стремительно развивается, дорабатывается и старается решать существенные недостатки С++ и других языков программирования.

Среди проектов, в которых компания Evrone использует Rust, можно отметить крупную ERP-систему сети ресторанов. В ней на Rust реализуется микросервис, который выдает пользователю информацию о ближайшем заведении. Также интересна реализация на Rust в нашем собственном сервисе непрерывной интеграции Vexor. На этом языке сделана диспетчеризация задач, шедулинг их выполнения и агент, управляющий изоляцией запущенных задач на рабочих машинах, автоматический закупщик мощностей и системы логирования.

Разработка с использованием Rust через несколько лет может стать гораздо более востребованной, а в отдаленной перспективе и вовсе потеснить нынешних лидеров.

Источник

Чем Rust отличается от «плюсов»: откровение ветерана С++

Rust часто называют преемником C++. Дмитрий Свиридкин рассказал на суровом программистском языке, так ли хорош любимчик пользователей Stack Overflow.

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Polina Vari для Skillbox Media

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Программист. Разрабатывает на C++ и Rust решения для платформы компьютерного зрения в Arrival. Автор сборника материалов по C++.

Я решил попробовать Rust, потому что устал отлавливать на код-ревью (и не только) одни и те же ошибки в «плюсах». Обязательно кто-нибудь объявит статик-лямбду и захватит в неё по ссылке нестатический временный объект. А когда код с такими ошибками коммитят, он проходит тесты, предполагающие однократный запуск. Программа попадает в продакшен, где запускается пару раз и падает. На поиск и отладку багов уходит много сил и времени.

В Rust нет бардака с библиотеками

У С++ всегда было две проблемы: недостаточная квалификация разработчиков и отсутствие нормальных пакетных менеджеров.

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

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Например, я видел реализации std::optional, которые не вызывают деструктор, даже если тип нетривиально деструктурируемый. Тогда как стандартная реализация — это куча boilerplate-кода, который даже командой из трёх-четырёх человек невозможно отладить.

Получается полный бардак. Часть кода покрывают тестами, она кое-как работает, а когда начинаешь детально тестировать — тут дедлок, там use-after-free и так далее. В Rust эти заботы можно частично переложить на плечи компилятора, но с ним иногда приходится бороться: богатая система типов требует более педантичной работы.

Чтобы писать на Rust, мне не пришлось менять IDE. Просто подключил к VS Code code-assistant rust-analyzer (это что-то вроде майкрософтовского IntelliSense). На прошлой работе писали в CLion от JetBrains. У неё есть неплохой плагин для Rust, но при рефакторинге он может наделать делов и оказать медвежью услугу. Так что IDE от JetBrains научили меня не доверять авторефакторингу — обязательно что-нибудь да сломается. Поэтому стараюсь аккуратно рефакторить сам.

Система типов в Rust защищает от ошибок

Бизнес-логика — именно то, что нужно писать на Rust, потому что с ним тяжело ошибиться. Ещё на прошлой работе мы запилили плагин — в качестве proof of concept того, что на Rust вообще можно создавать плагины к большому SDK. Логика была примитивная: принять список слов и проверить, совпадает ли с ним input.

Почему такой простой плагин? Потому что больше никто в команде не знал Rust. Язык молодой, и пока на нём мало кто пишет. Создавать проекты, которые может поддерживать только один разработчик, невыгодно. Проще найти «плюсовиков», поэтому C++ никуда не исчезнет.

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

На новой работе я перевожу часть проекта с «плюсов» на Rust. Язык подкупил меня мощной системой типов, которая позволяет выразить зависимости между временами жизни объектов. В языках с ещё более мощными системами типов, например с зависимыми типами, можно проверять статически рантаймовые ограничения. Например, запретить функции принимать пустые строки — компилятор проверит.

Однако у таких мощных языков есть общая проблема: вы замучаетесь доказывать компилятору, что код работает правильно и ничего в нём не нужно исправлять. К счастью, Rust не совсем такой, это золотая середина: с одной стороны, его система типов достаточно строгая, чтобы защитить вас от распространённых ошибок. С другой — не настолько строгая, чтобы приходилось мучиться с ней лишнего.

Программы на Rust без стороннего кода сравнимы по скорости с «плюсовыми»

На прошлой работе я переписывал большой графовый алгоритм — без unsafe-кода, с контейнерами из стандартной библиотеки.

По производительности программа была всего на 10% медленнее «плюсовой». При этом обошлись без стороннего кода. Считаю, что результат хороший. Под C++ пришлось три месяца искать hashmap и перебирать варианты: в одной выравнивание как-то хитро сконфигурировано и приводит к segfault, в другом exception вылетает, если хеш плохой, третий вообще уже четыре года не поддерживается.

Что же касается бенчмарков, то всегда можно подобрать тест, где выиграет нужный язык — хоть С++, хоть Rust. Достаточно знать тонкости работы с памятью в конкретном языке. Я, например, могу написать пример кода на Rust без лишних аллокаций, а в «плюсах» у аналогичной программы они будут, потому что организовать там safe по-другому нельзя. В общем, обсуждать производительность нужно на конкретном примере.

Code-assistant rust-analyzer отлично работает с шаблонами

В последнее время я оборачиваю небезопасные библиотеки языка С, чтобы подцепиться к каноническому Rust API. Если бы сразу начал писать на «плюсах», уже давно бы закончил и общался с железом, к которому эта библиотека поставляется. А так как пишу на Rust, то пришлось целую неделю аккуратно оборачивать код в канонические Rust-структуры. Столкнулся с тонкостями системы типов: вариантностью ссылок, контравариантностью типов. Если не обращать на них внимания, то safe-обёртка над C API будет некорректной.

Оборачивать низкоуровневый unsafe-код в safe на Rust довольно долго, но оно того стоит. «Плюсовой» IntelliSense вряд ли сравнится с мощным rust-analyzer и справится далеко не со всем кодом, особенно с шаблонами.

Возможно, с появлением стандарта С++20 появятся хинты и IntelliSense научится подсказывать внутри шаблонного кода, если в параметрах указать концепт. Думаю, раньше всех эту фичу внедрит в свои IDE JetBrains — если уже не начала втихаря над ней работать. Шаблоны без концептов в «плюсах» всегда работали плохо: стоит поставить неподходящий аргумент — и компилятор выдаёт огромные сообщения об ошибках. Пока у анализаторов Rust гораздо больше возможностей, да и писать шаблонный однотипный код на нём получается гораздо быстрее.

У Rust настоящая zero-cost abstraction

Помимо Rust, я присматривался и к другим языкам. Три года назад, когда впервые сменил работу, думал погрузиться в светлый мир JVM и написать что-нибудь на Kotlin. Но языки вроде Scala, Java и Kotlin можно применять далеко не везде. Виртуальные машины создают дополнительную нагрузку и для встраиваемого ПО в микрокомпьютерах не подходят. В таких системах пишут на чистом С, С++ или совсем страшных штуках вроде MISRA C.

У Rust, скомпилированного в native, нет дополнительного рантайма. RAII, деструкторы, конструкторы как в «плюсах». Только у Rust линейные типы и zero-cost с ними настоящий, а у C++ — нетривиальный деструктор у типа, и хоть убейтесь, но не получится передать его значение через регистры.

Ещё есть Zig — он очень похож на Rust. Там, например, тоже есть проверка lifetime, но организована она иначе, и то, как это сделано в Rust, мне нравится больше. Других языков с проверкой lifetime я не знаю, а в языках со сборщиками мусора она не нужна: если есть ссылка на объект, значит, он точно живой.

В Go механизм похожий, но там есть сборщик мусора. Мне предлагали перейти на него четыре года назад. Я попробовал, и синтаксис меня рассмешил. Стоит автоформатеру неправильно перенести строки, и программа не скомпилируется. А всё из-за неявной расстановки точек с запятой.

С похожей проблемой я сталкивался, когда мы в первый раз подключали сторонний форматер для «плюсов» — кажется, это был Uncrustify. Он убрал лишние фигурные скобки, и размер критических секций у меня резко вырос. Да уж, отличный форматер — поменял поведение программы. Мог бы просто весь код снести.

В Rust более лаконичный синтаксис, но к нему нужно привыкнуть

Вообще, синтаксис Rust меня вначале сильно раздражал, но я уже почти смирился с ним.

Раздражает символ ; в конце expression, который меняет возвращаемый тип на аналог сишного void. Поставил точку с запятой — программа перестаёт компилироваться. А компилятор молотит type-чекером, который занимает целое ядро, чтобы rust-analyzer и IDE написали красным: «Смотри, у тебя тут типы не сошлись».

Хорошо хоть в экосистеме Rust пофиксили много ошибок и в поставке уже есть официальный форматер, который всё делает правильно. Конечно, тоже есть проблемы. Например, если вы хотите сделать что-то серьёзное с пакетными менеджерами, например сложить собранные артефакты в каталог, то придётся вручную писать поверх скрипты, например на Bash. Штатными средствами это сделать либо нельзя, либо они unstable.

В целом я свыкся с упоротым синтаксисом и краткими ключевыми словами, но всё равно считаю, что они должны состоять хотя бы из трёх символов. Я люблю называть свои переменные fn, а мне его предлагают в качестве ключевого слова. С другой стороны, минималистичный синтаксис — это хорошо.

Лямбды можно писать кратко и без ключевого слова return — это экономит кучу времени. Зато когда после этого переключаешься на С++, то всё время забываешь писать return и, указав тип возврата, получаешь функции с неопределённым поведением. В С++ синтаксис лямбд вообще напоминает синтаксис обычных функций, только trailing return type сделали — ну, и на том спасибо, что уж там. А скобки и return нужно писать обязательно, иначе будете ждать от функции int, а она ничего не вернёт.

При этом Rust не панацея

Тех, кто только планирует погрузиться в Rust, предупреждаю: это не панацея от всех болячек C++. Он защищает вас от гонки данных через проверку borrow checker, но пропускает дедлоки. Защищает от use-after-free, но только в safe-подмножестве. Если же работаете с unsafe — у вас, по сути, будет тот же С++, только с более продвинутой стандартной библиотекой.

ламидий раст что это. Смотреть фото ламидий раст что это. Смотреть картинку ламидий раст что это. Картинка про ламидий раст что это. Фото ламидий раст что это

Хотя и здесь не всё так однозначно. Многие важные фичи, например для разработки драйверов или встроенного ПО, остаются нестабильными, а значит, писать на Rust серьёзные проекты пока рискованно. По этой причине от Rust часто отказываются в пользу C++, где всё давно stable и unsafe.

Источник

Распространённые заблуждения о временах жизни в Rust

(прим. переводчика: времена жизни (lifetimes) — это одна из самых запутанных вещей в Rust, которая часто вызывает затруднение у новичков, даже несмотря на официальную документацию. Разъяснения по отдельным аспектам времён жизни есть, но они все разбросаны по разным источникам и ответам на Stack Overflow. Автор статьи собрал в одном месте и разъяснил множество связанных с временами жизни вопросов, что и делает эту статью столь ценной (я и сам почерпнул новое для себя отсюда). Я решил перевести её, чтобы дать возможность прочитать её тем, кто не владеет английским в достаточной степени, чтобы свободно читать оригинал, а также для того, чтобы повысить известность этой статьи среди русскоязычного Rust-сообщества)

19 мая 2020 г. · 37 минут · #rust · # lifetimes

Оглавление

Вступление

Когда-то я был подвержен всем этим заблуждениям, сейчас же вижу, как многие новички борются с ними. Некоторые используемые мной термины могут быть нестандартными, поэтому для обозначения вкладываемого в них смысла я привожу таблицу со значениями.

Заблуждения

В двух словах: время жизни переменной — это статически проверяемый компилятором промежуток времени, в течение которого валидны обращения к данным, лежащим по адресу, сохранённому в переменной. Следующие

6500 слов я потрачу на более подробный рассказ о том, где обычно возникает путаница.

1) T содержит только владеющие типы

Это заблуждение больше относится к обобщённым типам, чем к временам жизни, но обобщённые типы и времена жизни тесно связаны в Rust, поэтому невозможно говорить об одном, не говоря о другом. В любом случае:

Переменная типаT&T&mut T
Примерыi32&i32&mut i32

Программа выше не компилируется, как и ожидалось:

Ключевые выводы

Ошибочные выводы

Что справедливо по отношению к static переменным:

‘static время жизни, вероятно, было названо так из-за времён жизни по умолчанию static переменных, ведь так? Так что логично, что время жизни ‘static должно следовать тем же правилам, не так ли?

Ключевые выводы

3) &’a T и T: ‘a — это одно и то же

Это заблуждение является обобщением заблуждения выше.

Ключевые выводы

4) мой код не является обобщённым и не имеет времён жизни

Ошибочные выводы

Это удобное заблуждение сохраняется из-за правил вывода времён жизни (lifetime elision), позволяющих опустить аннотации времён жизни в функциях, поскольку компилятор Rust выведет их согласно следующим правилам:

Это довольно много, поэтому давайте рассмотрим несколько примеров:

Если вы когда-нибудь писали:

то тогда повсюду в вашем коде есть выведенные аннотации времён жизни.

Ключевые выводы

5) если мой код компилируется, то мои аннотации времён жизни верны

Ошибочные выводы

Программа на Rust может быть технически компилируемой, но в то же время семантически неверной. Рассмотрим пример:

Ой! Ошибка компиляции:

Отнюдь, текущие аннотации времён жизни на самом деле являются источником ошибки! Это особенно трудно заметить, потому что ошибочные аннотации жизни опущены. Давайте выпишем развёрнутые аннотации времён жизни, чтобы получить более чёткое представление о проблеме:

Это совсем не помогло. Я всё ещё в замешательстве. Вот хорошая уловка, которую знают только профессионалы Rust: давайте аннотациям времён жизни осмысленные имена. Попробуем ещё раз:

Теперь, рассматривая предыдущую версию нашей программы, мы видим, что она явно была ошибочной. Так почему же Rust скомпилировал ее? Ответ прост: это было безопасным использованием памяти (memory safe).

Анализатор заимствований (borrow checker) Rust-а заботится о аннотациях времён жизни в программе только до той степени, до которой он может использовать их для статической проверки безопасности работы с памятью. Rust с радостью скомпилирует программы, даже если аннотации времён жизни содержат семантические ошибки и из-за этого программа становится излишне строгой.

Вот простой пример, который противоположен предыдущему: правила вывода времён жизни Rust в данном случае семантически корректны, но мы непреднамеренно пишем очень ограниченный метод с нашими собственными ненужными явными аннотациями времён жизни.

Ключевые выводы

6) трейт-объекты за владеющими указателями не имеют времён жизни

Ранее мы обсуждали правила Rust для вывода времён жизни применительно к функциям. У Rust также есть подобные правила для трейт-объектов:

Всё это звучит очень сложно, но это можно выразить коротко как «ограничения времени жизни трейт-объекта выводятся из контекста». Изучив несколько примеров, мы увидим, что выведенные времена жизни довольно интуитивны, поэтому нам не нужно запоминать формальные правила:

Конкретные типы, которые реализуют трейты, могут иметь ссылки, и, таким образом, иметь ограничения времён жизни, поэтому созданные из них трейт-объекты имеют соответствующие времена жизни. Также вы можете реализовать трейты непосредственно для ссылок, которые, очевидно, имеют ограничения времён жизни:

В любом случае, это стоит повторить, поскольку это часто сбивает с толку новичков, когда они преобразуют функцию из использующей трейт-объекты в обобщённую или наоборот. Рассмотрим пример:

Оно выдаёт ошибку компиляции:

Отлично, компилятор говорит нам, как решить проблему. Давайте исправим её.

Ключевые выводы

7) сообщения об ошибках компиляции скажут мне, как исправить мою программу

Ошибочные выводы

Данное заблуждение — это предыдущие два, объединённые в один пример:

Эта программа выдаёт следующую ошибку:

Хорошо, давайте исправим проблему так, как говорит нам компилятор. Не будем обращать внимание на тот факт, что он, не говоря нам, автоматически выводит для нашего трейт-объекта ограничение времени жизни ‘static и что его рекомендуемое исправление основано на этом предположении:

Итак, теперь программа компилируется… Но действительно ли это то, чего мы хотим? Возможно, да, но возможно, что и нет. Компилятор не предложил никаких других исправлений, но этот вариант также применим:

Эта функция принимает все те же аргументы, что и в предыдущая версии, и даже сверх этого! Делает ли это её лучше? Необязательно, это зависит от требований к нашей программе. Данный пример несколько абстрактный, поэтому давайте рассмотрим более простой и очевидный случай:

Сообщение об ошибке рекомендует аннотировать оба аргумента и возвращаемое значение одинаковым временем жизни. Если бы мы так сделали, наша программа бы скомпилировалась, но эта функция чрезмерно ограничила бы тип возвращаемого значения. На самом деле мы хотим этого:

Ключевые выводы

8) время жизни может расти и сокращаться во время исполнения

Ошибочные выводы

Этот код не компилируется:

Этот код также не компилируется и выдает ту же ошибку, что и пример выше:

Времена жизни должны быть статически проверены во время компиляции, и анализатор заимствований выполняет только очень ограниченный анализ потока управления, поэтому он предполагает, что каждый блок в операторе if-else и каждая ветвь выражения match могут быть выполнены, а затем выбирает самое короткое из возможных времён жизни для переменной. Как только переменная ограничена временем жизни, она ограничена этим временем жизни навсегда. Время жизни переменной может только сокращаться, и это сокращение полностью определяется на этапе компиляции.

Ключевые выводы

9) ослабление mut-ссылок до разделяемых безопасно

Ошибочные выводы

Вы можете передать mut-ссылку в функцию, ожидающую разделяемую ссылку, потому что Rust неявно перезаимствует mut-ссылку как неизменяемую:

Интуитивно это понятно, поскольку в повторном заимствовании mut-ссылки как иммутабельной нет ничего страшного, ведь так? На удивление — нет, так как программа ниже не компилируется:

Выдаёт следующую ошибку:

Переменная изменяемо заимствуется, но затем немедленно и безоговорочно перезаимствуется как неизменяемая, а затем ссылка отбрасывается. Почему Rust обращается с неизменяемым повторным заимствованием так, как будто у него все еще есть исключительное время жизни mut-ссылки? Хотя конкретно в приведенном выше примере проблем нет, предоставление возможности ослабления всех mut-ссылок до разделяемых действительно создает потенциальные проблемы безопасного доступа к памяти:

Дело в том, что когда вы повторно заимствуете mut-ссылку как разделяемую, вы получаете ссылку, но с некоторым подвохом: она продлевает время жизни изначальной ссылки на время перезаимствования, даже если та уже не используется. Использовать перезаимствованную разделяемую ссылку очень сложно, потому что она неизменяемая, но при этом не может пересекаться с другими разделяемыми ссылками. Перезаимствованная разделяемая ссылка имеет все минусы и разделяемой ссылки, и изменяемой, и не имеет плюсов ни той, ни другой. Я считаю, что повторное заимствование мутабельной ссылки как разделяемой должно считаться в Rust анти-паттерном. Знать этот анти-паттерн важно, чтобы вы могли легко заметить его в коде, подобном этому:

Даже если вы избегаете повторных заимствований в сигнатурах функций и методов, Rust по-прежнему выполняет автоматические неявные повторные заимствования, поэтому с этой проблемой легко можно столкнуться, не распознав её:

Да, это несколько неловко и неуклюже, но это — жертва, которую мы приносим на Алтарь Безопасной Работы С Памятью.

Ключевые выводы

10) замыкания следуют тем же правилам вывода времён жизни, что и функции

Это скорее подвох, нежели заблуждение.

Замыкания, несмотря на то, что они являются функциями, не следуют тем же правилам вывода времён жизни, что и функции.

После рассахаривания мы получаем:

Для этого несоответствия нет удовлетворительной причины. Сначала замыкания были реализованы с выводом типов, отличным от функций, и теперь мы застряли с этим навсегда, потому что в наше время унификация их поведения стало бы изменением, ломающим обратную совместимость. Так как же мы можем явно аннотировать тип замыкания? Вот доступные нам варианты:

Уверен, вы уже заметили в приведенных выше примерах, что когда на типы замыканий накладываются ограничения трейтов замыканий, они следуют обычным правилам вывода времён жизни для функций.

Тут нет какого-то урока или озарения, оно просто есть.

Ключевые выводы

Ранее я показал следующий пример:

Некоторые читатели связались со мной, чтобы спросить, существует ли на практике какая-то разница между этими двумя вариантами. Сначала я не был уверен, но после некоторого расследования я могу заявить, что, к сожалению, ответ на это вопрос утвердительный, разница есть.

Однако это приведение не работает, когда ссылки являются частью сигнатуры функции, поэтому этот код не компилируется:

И выдаёт эту ошибку компиляции:

Ключевые выводы

Заключение

Обсуждение

Обсудите эту статью на

Контакты

Получайте уведомления о будущих публикациях в блоге

Дальнейшее чтение

Переводчик выражает признательность за помощь в переводе статьи русскоязычному сообщество Rust, в особенности nlinker.

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *