Fatal error раст

Статья была создана для того, чтобы пользователи смогли исправить различные ошибки возникающие в игре Rust. Подробное решение ошибок в игре раст.

На чтение 9 мин Просмотров 32.2к. Опубликовано 18.07.2019 Обновлено 18.07.2019

1) Проблема:

Вылетает игра при запуске, на стадии Bootstrap Warmup
Вылетает игра при запуске, на стадии Bootstrap Systems
Вылетает игра при запуске, на стадии Running self check
Вылетает игра при вводе IP в консоль.
При вводе IP в консоль появляется ошибка No Token Data.

Решение

Закройте Steam и попробуйте зайти снова, если не помогло, то:
1. Откройте “панель управления Windows”, выберите раздел “Учётные записи пользователей” (для windows 7 включить показ – мелкие значки),затем выберите “Управление другой учётной записью”, “Создание учётной записи”.
2. Введите/выберите:
имя профиля строго на англ. языке (к примеру, Vasia), обязательно поставьте пароль
тип учётной записи – Администратор.
3. Нажмите кнопку “Создание учётной записи”.
4. Теперь откройте папку с игрой и
5. Наведите мышку на Rust_Client.exe, зажмите Shift и ПКМ откройте контекстное меню, выберите пункт “Запустить от имени другого пользователя”
6. В окне ввода введите имя и пароль только что созданной учётной записи и нажмите ОК
7. Играйте.

Содержание

  1. Вылетает игра при запуске, на стадии Bootstrap Shaders
  2. При подключении к серверу Wrong connection protocol: Client update required!
  3. Загрузка карты зависла, ошибка Oops! “The game crashed” или в консоли Out of memory
  4. Disconnected: Time Out или Disconnected: Failed to establish connection – no response from remote
  5. При подключении к серверу ошибка EAC: unconnected
  6. Rust launcher error: Loading error – EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled
  7. Rust launcher error: Loading error – CreateService failed
  8. Rust launcher error: NetworkDomainNameError – DNS resolve to EasyAnticheat network failed!
  9. Бесконечная загрузка terrain shadows
  10. Вылетает из Rust на рабочий стол
  11. Rust просто не запускается или пишет прекращена работа программы
  12. Не просыпается персонаж
  13. Почему игра не ищет сервера
  14. Rust Launcher Error:LoadingError – EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled
  15. Ошибка steam Auth:K_EAuthSessionResponseVACCheckTimedOut
  16. Бесконечная загрузка Terrain Mesh
  17. Вылетает игра на Shader warmap 
  18. Бывает такое, что при загрузке на сервер мы получаем такую надпись You are already connected 
  19. Зависает на receiving data 
  20. Вылетает на Loading level Prosedural Map или Loading level HAPISISLAND
  21. Черное небо
  22. При заходе на сервер пишет Disconnected: EAC Network: Disconnected
  23. При заходе на сервер вылезает окошко с надписью “ops the game crashed”, оперативной памяти более 8 гигабайт и система 64 разрядная
  24. RustNative.dll
  25. HEIGHT MAP
  26. EasyAntyCheat disconnect 
  27. Rust Launcher Error: LoadingError – StartService failed(1058)
  28. Зависает на Client ready
  29. Не открывается инвентарь и чат
  30. rust launcher error game error – shellexecute failed with code 5
  31. Error: NetworkError – Could not connect to the EasyAntiCheat network!
  32. Connection attempt failed
  33. Rust Launcher Error: LoadingError – StartService failed(1450)
  34. Rust Launcher Error: FatalError – Game startup failed. Error Code: 19 
  35. Rust launcher Error : LauncherFailure – WaitForSingleObject Failed
  36. Зависает при открытии чата , либо после нескольких минут игры
  37. Rust Launcher Error: LauncherFailure – Failed to start the game
  38. Rust launcher error launch failure error validating easyanticheat code signing certificate
  39. Rust Launcher Error: LauncherFailure – Game crash. Error Code:20
  40. Rust Launcher EasyAntiCheat – Download Update…1%

Вылетает игра при запуске, на стадии Bootstrap Shaders

Решение

Обновите драйвера для видеокарты, также установите полный пакет Microsoft Visual C++ и Net framework 4.5.2 затем запускайте игру с максимальными настройками графики.

При подключении к серверу Wrong connection protocol: Client update required!

Решение

У вас старая версия, скачайте актуальную версию клиента.

Загрузка карты зависла, ошибка Oops! “The game crashed” или в консоли Out of memory

https://steamuserimages-a.akamaihd.net/ugc/843714712225997625/7873230879345DF22851B5210261BA7C3A208109/

Решение

Игре не хватило оперативной памяти. Для нормальной игры нужно, как рекомендуют разработчики 64-разрядную Windows и не менее 4-6 гб ОЗУ. Также возможны вылеты на рабочий стол без каких либо ошибкок ( возможно из-за нехватки оперативной памяти)

Disconnected: Time Out или Disconnected: Failed to establish connection – no response from remote

Решение

Произошло отключение от сервера, нужно подождать

При подключении к серверу ошибка EAC: unconnected

Решение

Запускайте игру через RustClient.exe, если не помогло, то переустановите EAC.

Как переустановить EasyAntiCheat (EAC)

1. Заходим в папку EasyAntiCheat которая находится в папке с игрой
2. Запускаем EasyAntiCheat_Setup.exe
3. В появившемся окне выбираем Uninstall , В графе “Game selested” Rust и нажимаем Next
4. Запускаем EasyAntiCheat_Setup.exe
5. В появившемся окне выбираем Install , В графе “Game selested” Rust и нажимаем Next
Также прошу обратить внимание, что антивирусное по блокирует установку EAC, поэтому рекомендую временно отключить. Проверить игру на целостность.

Rust launcher error: Loading error – EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled

Решение

Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
В командной строке введите следующую команду и нажмите клавишу ВВОД:
bcdedit /set TESTSIGNING OFF
Закройте окно командной строки и перезагрузите компьютер.

Rust launcher error: Loading error – CreateService failed

Решение

Эта ошибка происходит, если EAC уже запущен. Откройте диспетчер задач и закройте процессы игры, а также EasyAntiCheat.exe. Перезагрузитесь.

Rust launcher error: NetworkDomainNameError – DNS resolve to EasyAnticheat network failed!

Решение

По какой-то причине не удалось получить ip
Очистите локальный кэш DNS. Для очистки выполните следующие команды в командной строке: ipconfig /flushdns

Бесконечная загрузка terrain shadows

Решение

Видекарта не может обработать данные ( попробуйте обновить драйвера)

Вылетает из Rust на рабочий стол

Решение

скорее всего у вас 32-х битная система, для игры требуется x64

Rust просто не запускается или пишет прекращена работа программы

Решение

Проверьте наличие установленного программного по. такого как Net framework 4.5.2+Microsoft visual c++ 2005, 2008, 2010, 2012 и тд.

Не просыпается персонаж

Решение

Нажать f1 и прописать wakeup или команду respawn

13) Проблема:

Почему игра не ищет сервера

Решение

Проследите, чтобы игру не блокировал ваш антивирус и firewall windows, а также возможно вы подписаны на бета программы. Для того что бы решить эту проблему нужно просто от них отписаться, сделать это можно по следующему алгоритму:
Выйти из игры.
Зайти в библиотеку Steam.
Находим ярлык игры Rust, щелкаем по нему ПКМ и выбираем Свойства.
Находим вкладку «Бета» (BETAS) в окне.
И в ней выбираем: «NONE — Opt out of all beta programs».

Rust Launcher Error:LoadingError – EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled

Решение

Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
В командной строке введите следующую команду и нажмите клавишу ВВОД:
bcdedit /set TESTSIGNING OFF
Закройте окно командной строки и перезагрузите компьютер.
Если этот способ не помог устранить проблему, воспользуйтесь способом 2.

Способ 2:
Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
В командной строке введите следующие команды, нажимая после каждой из них клавишу ВВОД.
bcdedit.exe -set loadoptions ENABLE_INTEGRITY_CHECKS
bcdedit.exe -set TESTSIGNING OFF
Закройте окно командной строки и перезагрузите компьютер[/b]

Ошибка steam Auth:K_EAuthSessionResponseVACCheckTimedOut

https://steamuserimages-a.akamaihd.net/ugc/843714472258072929/D06B05C0AF9AC24B6A2281EC11812BC076C067D7/

Решение

Проверка на читы (со временем это пройдет)

Бесконечная загрузка Terrain Mesh

Решение

Чаще всего возникает из-за 32 битных систем

Вылетает игра на Shader warmap 

Решение

Вылет происходит из-за слабых видеокарт, которые не могут обработать данные. Попробуйте обновить драйвер до последней версии, если не поможет, то игру вы не запустите.

Бывает такое, что при загрузке на сервер мы получаем такую надпись You are already connected 

Решение

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

Зависает на receiving data 

Решение

Установить Microsoft visual c++ 2013 версии x86 и x 64 ( запускать игру на diretrix 9.0)

Вылетает на Loading level Prosedural Map или Loading level HAPISISLAND

Решение

Можно попробовать обновить драйвер на видеокарту
Запускайте игру на DiretcX 9.0

Черное небо

Решение

Возникает на слабых видеокартах. Ждем когда будет новый патч, который исправит данную проблему.

При заходе на сервер пишет Disconnected: EAC Network: Disconnected

Решение

Что-то блокирует связь с серверами EAC. Попробуйте выключить антивирус и firewall windows

Далее…

При заходе на сервер вылезает окошко с надписью “ops the game crashed”, оперативной памяти более 8 гигабайт и система 64 разрядная

Решение

На ноутбуках может быть то, что игра по умолчанию будет использовать интегрированную видеокарту и нужно переключиться на дискетную. 
Для этого запускаем панель управления nvidia > управления параметрами 3D > выбираем вкладку программные настройки и в списке ищем Rust, после во втором пункте предпочтение выбираем высокопроизводительный процессор Nvidia.

RustNative.dll

Решение

Данная ошибка может возникать из-за несовместимости с системой, а именно windows xp, vista, а также на некоторых mac os. На них игра не запустится, так как отсутствуют некоторые библиотеки.

HEIGHT MAP

Решение

Зависает или вылетает на HEIGHT MAP. Видеокарта недостаточно мощная и не может обработать карту текстур ( карта текстур это постройки, которые находятся сейчас на севере и тд) , обновите драйвер до последней весии, если это не поможет запускаем игру на Dx 9.0

EasyAntyCheat disconnect 

Решение

Отключите гарнитуру (наушники) 
EasyAntyCheat – у некоторых выдает глюк с ней

Rust Launcher Error: LoadingError – StartService failed(1058)

Решение

Служба не может быть запущена, поскольку она либо отключена либо он не имеет связанного с ней устройства
Написать в командной строке (cmd) sc delete easyanticheat
если не поможет добавить в исключение антивируса файл EasyAntiCheat.sys

Зависает на Client ready

Решение

Чаще всего бывает из-за нехватки оперативной памяти, блокировке соединения антивирусом

Не открывается инвентарь и чат

Решение

При запуске раста когда открывается окно запуска(Лаунчер игры) с разрешением и графикой, жмем input там идем вниз и ищем слово cancel его первое значение escape , а 2 значение тоже ставим на escape

rust launcher error game error – shellexecute failed with code 5

Решение

Заходим в папку с игрой и ставим совместимость на раст клиент с windows vista 1 ( убираем галочку выполнять от администратора) если не заходит то оставляем ее

Error: NetworkError – Could not connect to the EasyAntiCheat network!

Решение

Антивирус блокирует соединение Eac, нет соединения с серверами античита, отключить антивирус, переустановить античит

Connection attempt failed

Решение

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

Rust Launcher Error: LoadingError – StartService failed(1450)

https://steamuserimages-a.akamaihd.net/ugc/843714712226049168/637073C3562A10520EB1550305527A56FE27DAD6/

Решение

Отключить и если не поможет, то удалить антивирус и переустановить Eac

Rust Launcher Error: FatalError – Game startup failed. Error Code: 19 

Решение

Чаще всего возникает из-за антивируса AVG

Rust launcher Error : LauncherFailure – WaitForSingleObject Failed

Решение

Cвойства -> локальные файлы -> проверить целостность кэша. 
Если это не работает, то проблема в антивирусе AVG

Зависает при открытии чата , либо после нескольких минут игры

https://steamuserimages-a.akamaihd.net/ugc/843714712226037707/E7AB76033A71FFDE2A79056099BFAE3E6656684D/

Решение

Открываем Steam , заходим в свойства раста , параметры запуска и вписываем след строчку : -force-gfx-direct

Rust Launcher Error: LauncherFailure – Failed to start the game

Решение

Удалить антивирус, прописать в командной строке (cmd) sc delete easyanticheat

Rust launcher error launch failure error validating easyanticheat code signing certificate

https://steamuserimages-a.akamaihd.net/ugc/843714712226022880/B823482074C16A6700A544ABBB8F99E9E36EBD29/

Решение

Чаще всего из-за проверки обновлений windows. Скачать и установить обновления

Rust Launcher Error: LauncherFailure – Game crash. Error Code:20

https://steamuserimages-a.akamaihd.net/ugc/843714712226017737/5D94B6F08CBEE13B892E5415E95F731131EC5C13/

Решение

Античиту игры мешает программа КриптоПро, ее удаление поможет решить проблему. Также все подобные ошибки 19, 20, 21 и тд…с такой надписью, ошибка античита. Переустановить античит, при этом удалив антивирус и прочие программы, которые могут блокировать файлы

Rust Launcher EasyAntiCheat – Download Update…1%

https://steamuserimages-a.akamaihd.net/ugc/857225545731422224/5D20A753C3DA2334E334D2DBB96D636016EACF3B/

Решение

Данная проблема может появиться при блокировке файлов античит системы EAC, антивирусом или брандмауэром windows, а также другими защитными средствами. Даже в выключенном состоянии антивирус способен блокировать неугодные ему файлы.

Прочитать позже Отправить статью на e-mail Мы не собираем ваши данные и тем более не передаем их третьим лицам Отправить

Описание ошибок и их решения

1. Проблема:

  • Вылетает игра при запуске, на стадии Bootstrap Warmup
  • Вылетает игра при запуске, на стадии Bootstrap Systems
  • Вылетает игра при запуске, на стадии Running self check
  • Вылетает игра при вводе IP в консоль.
  • При вводе IP в консоль появляется ошибка No Token Data.

Решение: 

Закройте Steam и попробуйте зайти снова, если не помогло, то:
1. Откройте «панель управления Windows«, выберите раздел «Учётные записи пользователей» (для windows 7 включить показ — мелкие значки),затем выберите «Управление другой учётной записью«, «Создание учётной записи«.
2. Введите/выберите:
имя профиля строго на англ. языке (к примеру, Vasia), обязательно поставьте пароль
тип учётной записи — Администратор.
3. Нажмите кнопку «Создание учётной записи».
4. Теперь откройте папку с игрой и
5. Наведите мышку на Rust_Client.exe, зажмите Shift и ПКМ откройте контекстное меню, выберите пункт «Запустить от имени другого пользователя«
6. В окне ввода введите имя и пароль только что созданной учётной записи и нажмите ОК
7. Играйте.

2. Проблема:

  • Вылетает игра при запуске, на стадии Bootstrap Shaders

Решение:

Обновите драйвера для видеокарты, также установите полный пакет Microsoft Visual C++ и Net framework 4.5.2 затем запускайте игру с максимальными настройками графики.

3. Проблема:

  • При подключении к серверу Wrong connection protocol: Client update required!

Решение:

У вас старая версия, скачайте актуальную версию клиента.

4. Проблема:

  • Загрузка карты зависла, ошибка Oops! «The game crashed» или в консоли Out of memory.

Решение:

Игре не хватило оперативной памяти. Для нормальной игры нужно, как рекомендуют разработчики 64-разрядную Windows и не менее 4-6 гб ОЗУ. Также возможны вылеты на рабочий стол без каких либо ошибкок ( возможно из-за нехватки оперативной памяти)

5. Проблема:

  • Disconnected: Time Out или Disconnected: Failed to establish connection — no response from remote

Решение:

Произошло отключение от сервера, нужно подождать.

6. Проблема:

  • При подключении к серверу ошибка EAC: unconnected.

Решение:

  • Запускайте игру через RustClient.exe, если не помогло, то переустановите EAC.

Как переустановить EasyAntiCheat (EAC):

  • Заходим в папку EasyAntiCheat которая находится в папке с игрой
  • Запускаем EasyAntiCheat_Setup.exe
  • В появившемся окне выбираем Uninstall , В графе «Game selested» Rust и нажимаем Next
  • Запускаем EasyAntiCheat_Setup.exe
  • В появившемся окне выбираем Install , В графе «Game selested» Rust и нажимаем Next
  • Также прошу обратить внимание, что антивирусное по блокирует установку EAC, поэтому рекомендую временно отключить. Проверить игру на целостность.

7. Проблема:

  • При запуске игры появляется окно с ошибкой:
  1. Rust launcher error: Loading error — EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled
  2. Rust Launcher Error: LoadingError — EasyAntiCheat cannot run under Windows Test Signing Mode.

Решение:

  • Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
  • Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
  • В командной строке введите следующую команду и нажмите клавишу ВВОД:
  • bcdedit /set TESTSIGNING OFF
  • Закройте окно командной строки и перезагрузите компьютер.

8. Проблема:

  • При запуске игры появляется окно с ошибкой:
  1. Rust launcher error: Loading error — CreateService failed
  2. Rust launcher error: Loading error — An application using EasyAntiCheat is already running!

Решение:

  • Эта ошибка происходит, если EAC уже запущен. Откройте диспетчер задач и закройте процессы игры, а также EasyAntiCheat.exe. Перезагрузитесь.

9. Проблема:

  •  Rust launcher error: NetworkDomainNameError — DNS resolve to EasyAnticheat network failed!

Решение:

  • По какой-то причине не удалось получить ip
  • Очистите локальный кэш DNS. Для очистки выполните следующие команды в командной строке: ipconfig /flushdns

10. Проблема:

  • Бесконечная загрузка terrain shadows

Решение:

  • Видеокарта не может обработать данные (попробуйте обновить драйвера)

11. Проблема:

  • Вылетает из Rust на рабочий стол

Решение:

  • Скорее всего у вас 32-х битная система, для игры требуется x64

12. Проблема:

  • Rust просто не запускается или пишет прекращена работа программы

Решение:

  • Проверьте наличие установленного программного по. такого как Net framework 4.5.2+Microsoft visual c++ 2005, 2008, 2010, 2012 и тд.

13. Проблема:

  • Не просыпается персонаж

Решение:

  • Нажать F1 и прописать wakeup или команду respawn

14. Проблема:

  • Почему игра не ищет сервера?

Решение:

  • Проследите, чтобы игру не блокировал ваш антивирус и firewall windows, а также возможно вы подписаны на бета программы. Для того что бы решить эту проблему нужно просто от них отписаться, сделать это можно по следующему алгоритму:
  • Выйти из игры.
  • Зайти в библиотеку Steam.
  • Находим ярлык игры Rust, щелкаем по нему ПКМ и выбираем Свойства.
  • Находим вкладку «Бета» (BETAS) в окне.
  • И в ней выбираем: «NONE — Opt out of all beta programs».

15. Проблема:

  • Rust Launcher Error:LoadingError — EasyAntiCheat cannot run if Driver Signature Enforcement has been disabled

Решение:

  • Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
  • Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
  • В командной строке введите следующую команду и нажмите клавишу ВВОД:
  • bcdedit /set TESTSIGNING OFF
  • Закройте окно командной строки и перезагрузите компьютер.

Способ 2:

  • Нажмите кнопку Пуск , а затем введите команду cmd в поле поиска.
  • Щелкните правой кнопкой мыши файл cmd.exe в списке Программы и выберите команду Запуск от имени администратора.
  • В командной строке введите следующие команды, нажимая после каждой из них клавишу ВВОД.
  • bcdedit.exe -set loadoptions ENABLE_INTEGRITY_CHECKS
  • bcdedit.exe -set TESTSIGNING OFF
  • Закройте окно командной строки и перезагрузите компьютер

16. Проблема:

  • Ошибка steam Auth:K_EAuthSessionResponseVACCheckTimedOut

Решение:

  • Проверка на читы (со временем это пройдет)

17. Проблема:

  • Бесконечная загрузка Terrain Mesh

Решение:

  • Чаще всего возникает из-за 32 битных систем

18. Проблема:

  • Вылетает игра на Shader warmap

Решение:

  • Вылет происходит из-за слабых видеокарт, которые не могут обработать данные. Попробуйте обновить драйвер до последней версии, если не поможет, то игру вы не запустите.

19. Проблема:

  • Бывает такое, что при загрузке на сервер мы получаем такую надпись You are already connected

Решение:

  • Просто ждать, если перевести данные слова, то в них сказано будто вы уже присоединились и находитесь на этом сервере. Пройдет со временем. Можно также попробовать очистить кэш игры.

20. Проблема:

  • Зависает на receiving data

Решение:

  • Установить Microsoft visual c++ 2013 версии x86 и x64 ( запускать игру на diretrix 9.0)

21. Проблема:

  • Вылетает на Loading level Prosedural Map или Loading level HAPISISLAND

Решение:

  • Можно попробовать обновить драйвер на видеокарту
  • Запускайте игру на DiretcX 9.0

22. Проблема:

  • Черное небо

Решение:

  • Возникает на слабых видеокартах. Ждем когда будет новый патч, который исправит данную проблему.

23. Проблема:

  • При заходе на сервер пишет Disconnected: EAC Network: Disconnected

Решение:

  • Что-то блокирует связь с серверами EAC. Попробуйте выключить антивирус и firewall windows

24. Проблема:

  • При заходе на сервер вылезает окошко с надписью «ops the game crashed«, оперативной памяти более 8 гигабайт и система 64 разрядная

Решение:

  • На ноутбуках может быть то, что игра по умолчанию будет использовать интегрированную видеокарту и нужно переключиться на дискетную.
  • Для этого запускаем панель управления nvidia > управления параметрами 3D > выбираем вкладку программные настройки и в списке ищем Rust, после во втором пункте предпочтение выбираем высокопроизводительный процессор Nvidia.

25. Проблема:

  • RustNative.dll

Решение:

  • Данная ошибка может возникать из-за несовместимости с системой, а именно windows xp, vista, а также на некоторых mac os. На них игра не запустится, так как отсутствуют некоторые библиотеки.

26. Проблема:

  • HEIGHT MAP

Решение:

  • Зависает или вылетает на HEIGHT MAP. Видеокарта недостаточно мощная и не может обработать карту текстур ( карта текстур это постройки, которые находятся сейчас на севере и тд) , обновите драйвер до последней весии, если это не поможет запускаем игру на Dx 9.0

27. Проблема:

  • EasyAntyCheat disconnect и ничего не помогает, все программное по установлено

Решение:

  • Отключите гарнитуру (наушники)
  • EasyAntyCheat — у некоторых выдает глюк с ней

28. Проблема:

  • Rust Launcher Error: LoadingError — StartService failed(1058)

Решение:

  • Служба не может быть запущена, поскольку она либо отключена либо он не имеет связанного с ней устройства
  • Написать в командной строке (cmd) sc delete easyanticheat
  • если не поможет добавить в исключение антивируса файл EasyAntiCheat.sys

29. Проблема:

  • Зависает на Client ready

Решение:

  • Чаще всего бывает из-за нехватки оперативной памяти, блокировке соединения антивирусом

30. Проблема:

  • Не открывается инвентарь и чат

Решение:

  • При запуске Rust когда открывается окно запуска (Лаунчер игры) с разрешением и графикой, жмем input там идем вниз и ищем слово cancel его первое значение escape , а 2 значение тоже ставим на escape

31. Проблема:

  • rust launcher error game error — shellexecute failed with code 5

Решение:

  • Заходим в папку с игрой и ставим совместимость на раст клиент с windows vista 1 ( убираем галочку выполнять от администратора) если не заходит то оставляем ее

32. Проблема:

  • Error: NetworkError — Could not connect to the EasyAntiCheat network!

Решение:

  • Антивирус блокирует соединение EAC, нет соединения с серверами античита, отключить антивирус, переустановить античит

33. Проблема

  • Connection attempt failed

Решение:

  • Это не ошибка, а простое уведомление о том, что подключение не удалось. Почему оно не удалось неизвестно. Но может быть причина в интернет соединении
  • Если вы пользуетесь модемом, то пробуйте его перезагрузить. Иногда может возникать из-за потери пакетов игры.

34. Проблема:

  • Rust Launcher Error: LoadingError — StartService failed(1450)

Решение:

  • Отключить и если не поможет, то удалить антивирус и переустановить EAC

35. Проблема:

  • Rust Launcher Error: FatalError — Game startup failed. Error Code: 19

Решение:

  • Чаще всего возникает из-за антивируса AVG

36. Проблема:

  • Rust launcher Error : LauncherFailure — WaitForSingleObject Failed

Решение:

  • Cвойства -> локальные файлы -> проверить целостность кэша.
  • Если это не работает, то проблема в антивирусе AVG

37. Проблема:

  • Зависает при открытии чата , либо после нескольких минут игры

Решение:

  • Открываем Steam , заходим в свойства Rust , параметры запуска и вписываем след строчку : -force-gfx-direct

38. Проблема:

  • Rust Launcher Error: LauncherFailure — Failed to start the game

Решение:

  • Удалить антивирус, прописать в командной строке (cmd) sc delete easyanticheat

39. Проблема:

  • Rust launcher error launch failure error validating easyanticheat code signing certificate

Решение:

  • Чаще всего из-за проверки обновлений windows. Скачать и установить обновления

40. Проблема

  • Rust Launcher Error: LauncherFailure — Game crash. Error Code:20

Решение:

  • Античиту игры мешает программа КриптоПро, ее удаление поможет решить проблему. Также все подобные ошибки 19, 20, 21 и тд…с такой надписью, ошибка античита. Переустановить античит, при этом удалив антивирус и прочие программы, которые могут блокировать файлы

Изменено: Zilla, 15 февраля 2017 — 05:00

Опубликованное фото


    • 2
  • Наверх


15 февраля 2017 — 04:56

Одна из многопользовательских видеоигр на выживание ‘Ржавчина‘Был полностью выпущен в феврале 2018 г. после первого выпуска в 2013 г. С каждой миссией игра становится все интереснее. Однако у игроков на ПК возникает одна из распространенных проблем. при запуске игры e, g Ошибка запуска Rust или сбой каждый раз. Это буквально раздражает всех затронутых игроков, и если у вас тоже получается то же самое, то вы не одиноки. Здесь мы предоставили несколько простых в использовании способов исправить эту ошибку.

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

Ошибка запуска Rust или сбой после запуска игры: как исправить фатальную ошибку?

Оглавление

  • 1 Почему Rust продолжает вылетать?
  • 2 Минимальные системные требования:
  • 3 Рекомендованные системные требования:
  • 4 Ошибка запуска Rust или сбой после запуска игры: как исправить фатальную ошибку?

    • 4.1 1. Перезапустите Steam
    • 4.2 2. Перезагрузите компьютер
    • 4.3 3. Удалить DLL из Steam
    • 4.4 4. Обновите графический драйвер
    • 4.5 5. Обновите ОС Windows
    • 4.6 6. Обновить игру Rust
    • 4.7 7. Используйте выделенную видеокарту
    • 4.8 8. Проверить файлы игры

Почему Rust продолжает вылетать?

Могут быть возможные причины того, что Rust продолжает давать сбой на вашем ПК с Windows 10. Давайте взглянем.

  • Конфигурация вашего ПК несовместима с системными требованиями игры.
  • Некоторые файлы игры отсутствуют или повреждены.
  • На вашем компьютере установлена ​​устаревшая ОС Windows или графический драйвер.
  • Устаревшая версия DirectX.
  • Версия игры или клиента не обновляется.
  • Любое из наложенных приложений работает в фоновом режиме.
  • Брандмауэр Windows или антивирусная программа блокирует игру.

Минимальные системные требования:

  • Требуется 64-битный процессор и операционная система.
  • ОПЕРАЦИОННЫЕ СИСТЕМЫ: Windows 8.1 64-битная
  • Процессор: Intel Core i7-3770 / AMD FX-9590 или лучше
  • Объем памяти: 10 ГБ RAM
  • Графика: GTX 670 2GB / AMD R9 280 лучше
  • DirectX: Версия 11
  • Сеть: Широкополосное подключение к Интернету
  • Место хранения: 20 ГБ свободного места
  • Дополнительные примечания: Настоятельно рекомендуется использовать твердотельные накопители или ожидать более длительного времени загрузки, чем в среднем.

Рекомендованные системные требования:

  • Требуется 64-битный процессор и операционная система.
  • ОПЕРАЦИОННЫЕ СИСТЕМЫ: Windows 10 64-битная
  • Процессор: Intel Core i7-4690K / AMD Ryzen 5 1600
  • Объем памяти: 16 ГБ RAM
  • Графика: GTX 980 / AMD R9 Fury
  • DirectX: Версия 12
  • Сеть: Широкополосное подключение к Интернету
  • Место хранения: 20 ГБ свободного места
  • Дополнительные примечания: Настоятельно рекомендуется SSD.

Ошибка запуска Rust или сбой после запуска игры: как исправить фатальную ошибку?

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

1. Перезапустите Steam

  • Закройте клиент Steam, если он запущен.
  • Затем перейдите на панель задач и щелкните правой кнопкой мыши значок Steam> Нажмите «Выход».
  • Наконец, снова запустите клиент Steam.

2. Перезагрузите компьютер

Иногда система Windows или какие-либо фоновые службы могут вызывать сбой или ошибку при запуске, в основном при запуске любой игры. Поэтому всегда лучше и рекомендуется перезагрузить компьютер один раз, если вы где-то застряли, игра не запускается или появляется ошибка.

  • Щелкните меню «Пуск»> щелкните значок «Питание».
  • Там вам нужно выбрать опцию Restart. Нажмите на нее и дождитесь перезагрузки.
  • Как только ваш компьютер снова включится, запустите Steam и запустите игру Rust, чтобы проверить наличие проблемы.

Если в вашей системе Windows есть сбой или проблема с кешем, метод перезагрузки всегда пригодится.

3. Удалить DLL из Steam

Файл Steam.dll разработан Valve Corporation, который также прошел цифровую проверку и подписан. Это в основном позволяет системе легко запускать любую игру в клиенте Steam. Теперь, если ваша игра не запускается или работает некорректно, это также может произойти из-за того, что файл steam.dll поврежден или неуместен, или какое-то вредоносное приложение влияет на него и т. Д. Удалив файл steam.dll, вы сможете запустить игру.

  • Итак, вам нужно будет удалить файл steam_api64.dll в папке steam / steamapps / common / rust на вашем ПК. Убедитесь, что это конкретное место, где вы установили клиент Steam. По умолчанию он должен находиться на диске C:, но может быть и на других дисках, если вы изменили каталог.
  • Теперь, если вы не можете найти это место самостоятельно, вы можете выполнить следующее:

Этот ПК> C:> Program Files (x86)> Steam> steamapps> common> rust folder.

4. Обновите графический драйвер

  • Щелкните меню «Пуск»> введите «Диспетчер устройств» и щелкните его в результатах поиска.
  • Откроется страница диспетчера устройств. Здесь перейдите к адаптерам дисплея.
  • Щелкните значок стрелки вправо рядом с адаптерами дисплея, чтобы развернуть список.
  • Щелкните правой кнопкой мыши выделенную видеокарту и выберите «Обновить драйвер».
  • Затем нажмите Автоматический поиск обновленного программного обеспечения драйвера.
  • Он будет искать драйверы в Интернете. Если доступна последняя версия драйвера, она автоматически загрузит последнюю версию драйвера и установит ее. Вам просто нужно дождаться этого.
  • После этого вы получите сообщение «Windows успешно обновила ваши драйверы».

Если последняя версия недоступна, вы можете перейти к следующему способу.

5. Обновите ОС Windows

  • Нажмите «Пуск»> «Выбрать значок настроек».
  • Нажмите «Обновление и безопасность»> В разделе «Центр обновления Windows» вы получите уведомление о доступных обновлениях.
  • Если да, то нажмите кнопку «Загрузить» и дождитесь завершения процесса обновления. Он установит накопительное обновление для вашей системы на базе Windows 10 версии 1903 или выше.
  • Иногда из-за небрежности или неправильного уведомления может быть несколько ожидающих накопительных обновлений. Итак, не забудьте установить все ожидающие обновления и перезагрузить компьютер.

6. Обновить игру Rust

Вы всегда можете проверить обновления своей игры во время работы клиента Steam.

  • Откройте клиент Steam> Щелкните, чтобы выбрать игру Rust на левой боковой панели.
  • Появится интерфейс запуска игры Rust.
  • Здесь вы можете увидеть кнопку «Обновить» синего цвета. Если да, то нажмите на нее и пусть игра обновится автоматически.
  • После этого вы увидите кнопку «Воспроизведение» зеленого цвета. Нажмите «Играть» и наслаждайтесь!

7. Используйте выделенную видеокарту

Для Nvidia:

  • Щелкните правой кнопкой мыши на рабочем столе> выберите Панель управления Nvidia. (Вы также можете найти его на панели задач)
  • В разделе «Настройки 3D» вам нужно выбрать «Управление настройками 3D».
  • Нажмите Настройки программы> Обзор и выберите игру Rust из списка.
  • Затем выберите предпочтительный графический процессор и установите его в режим высокой производительности.

Для ATI / ATX:

  • Запустите AMD Radeon Settings, щелкнув правой кнопкой мыши на рабочем столе.
  • Теперь откройте настройки графики> Возможно, вам потребуется перейти к параметру PowerPlay.
  • Установите режим питания от сети или от аккумулятора для максимальной производительности.
  • Кроме того, вы можете перейти к 3D в настройках графики и установить высокий уровень.

8. Проверить файлы игры

Проверка файлов игры — еще одна важная вещь при сбое при запуске Rust. Это поможет игре работать должным образом, независимо от того, используете ли вы Steam или любую другую программу запуска. К счастью, вы можете сделать это прямо из программы запуска, что упрощает задачу.

  • Откройте программу запуска Steam на своем ПК.
  • Щелкните Библиотека> Щелкните правой кнопкой мыши игру Rust.
  • Выберите «Свойства»> «Щелкните вкладку» Локальные файлы «.
  • Здесь вам нужно будет нажать на Проверить целостность игровых файлов…
  • Он начнет проверку файлов Steam, и вы увидите индикатор выполнения.
  • Теперь, если все файлы доступны и работают правильно, появится сообщение об успешном завершении.
  • Если нет, то вы можете увидеть «1 файл не прошел проверку и будет повторно получен». (Может быть несколько неудачных файлов)
  • Просто закройте его и перезапустите клиент Steam. Все поврежденные или отсутствующие файлы будут автоматически исправлены.
  • Наконец, запускаем игру.

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

Субодх любит писать контент, будь то технический или другой. Проработав год в техническом блоге, он увлекается этим. Он любит играть в игры и слушать музыку. Помимо ведения блога, он увлекается сборками игровых ПК и утечками информации о смартфонах.

Error

cargo run
   Compiling stack_overflow v0.1.0 (/d/stack_overflow)                                                                        
    Finished dev [unoptimized + debuginfo] target(s) in 7.08s                                                                 
     Running `target/debug/stack_overflow`

thread 'main' has overflowed its stack
fatal runtime error: stack overflow
Аварийный останов (стек памяти сброшен на диск)

Rust Version

RUST STABLE:
rustc 1.31.1 (b6c32da9b 2018-12-18)

RUST NIGHTLY:
rustc 1.33.0-nightly (9eac38634 2018-12-31)

Code

use std::fmt::Write;
use std::ops::Deref;
use std::fmt;

//////The structure stores in itself the changeable reference and has to clean data in "drop" of structure.
#[derive(Debug)]
pub struct DebugSliceMutString<'a>(&'a mut String);



//Stack overflow <----
//assert_eq!(&null.my_debug(&mut string).unwrap(), "=");
impl<'a> PartialEq<str> for DebugSliceMutString<'a> {   
     fn eq(&self, other: &str) -> bool {
          self == other
     }
}



//Stack overflow <----
//assert_eq!(null.my_debug(&mut string).unwrap(), "=");
impl<'a> PartialEq<&str> for DebugSliceMutString<'a> {
     fn eq(&self, other: &&str) -> bool {
          self == other
     }
}

//If to take 'deref' that there is no overflow of a stack!!
//assert_eq!(*null.my_debug(&mut string).unwrap(), "=");
impl<'a> Deref for DebugSliceMutString<'a> {
     type Target = String;
     
     fn deref(&self) -> &String {
          self.0
     }
}

impl<'a> Drop for DebugSliceMutString<'a> {
     fn drop(&mut self) {
          self.0.clear()
     }
}



//MyTrait
pub trait MyDebug {
     fn my_debug<'a>(&self, w: &'a mut String) -> Result<DebugSliceMutString<'a>, fmt::Error>;
}

impl MyDebug for (usize, usize) {
     fn my_debug<'a>(&self, w: &'a mut String) -> Result<DebugSliceMutString<'a>, fmt::Error> {
          write!(w, "{}={}", self.0, self.1)?;

          Ok( DebugSliceMutString(w) )
     }
}

//


fn main() {
	//The buffer for an exception of frequent reallocations of memory
	let mut string = String::with_capacity(9);

	//Any other type, in this case (usize, usize) is more convenient
	let null =	(10, 20);
	

	// !!!!!!!
	//thread 'main' has overflowed its stack
	//fatal runtime error: stack overflow
	//Аварийный останов (стек памяти сброшен на диск)
	assert_eq!(	null.my_debug(&mut string).unwrap(), "=");


	// !!!!!!!
	//If to use Deref that there is no overflow of a stack!!
	//assert_eq!(	*null.my_debug(&mut string).unwrap(), "=");


	// !!!!!!!OR
	//thread 'main' has overflowed its stack
	//fatal runtime error: stack overflow
	//Аварийный останов (стек памяти сброшен на диск)
	//
	//let a = null.my_debug(&mut string).unwrap()
	//	.eq(&"=");
	//

	//
	println!("string, {}, capacity: {}", string, string.capacity());
}

Run

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=5bacc9a73f0ae7a38100da9d196b08d0

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

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

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

Содержание

Эта статья очень длинная, в основном потому, что мы начнем с самого начала — рассмотрения типов-сумм (sum type) и комбинаторов, и далее попытаемся последовательно объяснить подход Rust к обработке ошибок. Так что разработчики, которые имеют опыт работы с другими выразительными системами типов, могут свободно перескакивать от раздела к разделу.

  • Основы
    • Объяснение unwrap
    • Тип Option
      • Совмещение значений Option<T>
    • Тип Result
      • Преобразование строки в число
      • Создание псевдонима типа Result
    • Короткое отступление: unwrap — не обязательно зло
  • Работа с несколькими типами ошибок
    • Совмещение Option и Result
    • Ограничения комбинаторов
    • Преждевременный return
    • Макрос try!
    • Объявление собственного типа ошибки
  • Типажи из стандартной библиотеки, используемые для обработки ошибок
    • Типаж Error
    • Типаж From
    • Настоящий макрос try!
    • Совмещение собственных типов ошибок
    • Рекомендации для авторов библиотек
  • Заключение

Основы

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

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

Важным аспектом такого подхода к решению проблем является то, что такой анализ должен быть исчерпывающим (exhaustive). Другими словами, при использовании вариативного анализа должны быть рассмотрены все возможные случаи.

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

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

// Попробуйте угадать число от 1 до 10.
// Если заданное число соответствует тому, что мы загадали, возвращается true.
// В противном случае возвращается false.
fn guess(n: i32) -> bool {
    if n < 1 || n > 10 {
        panic!("Неверное число: {}", n);
    }
    n == 5
}

fn main() {
    guess(11);
}

Если попробовать запустить этот код, то программа аварийно завершится с сообщением вроде этого:

thread '<main>' panicked at 'Неверное число: 11', src/bin/panic-simple.rs:6

Вот другой, менее надуманный пример. Программа, которая принимает число в качестве аргумента, удваивает его значение и печатает на экране.

use std::env;

fn main() {
    let mut argv = env::args();
    let arg: String = argv.nth(1).unwrap(); // ошибка 1
    let n: i32 = arg.parse().unwrap();      // ошибка 2
    println!("{}", 2 * n);
}

Если вы запустите эту программу без параметров (ошибка 1) или если первый параметр будет не целым числом (ошибка 2), программа завершится паникой, так же, как и в первом примере.

Обработка ошибок в подобном стиле подобна слону в посудной лавке. Слон будет нестись в направлении, в котором ему вздумается, и крушить все на своем пути.

Объяснение unwrap

В предыдущем примере мы утверждали, что программа будет просто паниковать, если будет выполнено одно из двух условий для возникновения ошибки, хотя, в отличии от первого примера, в коде программы нет явного вызова panic. Тем не менее, вызов panic встроен в вызов unwrap.

Вызывать unwrap в Rust подобно тому, что сказать: «Верни мне результат вычислений, а если произошла ошибка, просто паникуй и останавливай программу». Мы могли бы просто показать исходный код функции unwrap, ведь это довольно просто, но перед этим мы должны разобратся с типами Option и Result. Оба этих типа имеют определенный для них метод unwrap.

Тип Option

Тип Option объявлен в стандартной библиотеке:

enum Option<T> {
    None,
    Some(T),
}

Тип Option — это способ выразить возможность отсутствия чего бы то ни было, используя систему типов Rust. Выражение возможности отсутствия через систему типов является важной концепцией, поскольку такой подход позволяет компилятору требовать от разработчика обрабатывать такое отсутствие. Давайте взглянем на пример, который пытается найти символ в строке:

// Поиск Unicode-символа `needle` в `haystack`. Когда первый символ найден,
// возвращается побайтовое смещение для этого символа. Иначе возвращается `None`.
fn find(haystack: &str, needle: char) -> Option<usize> {
    for (offset, c) in haystack.char_indices() {
        if c == needle {
            return Some(offset);
        }
    }
    None
}

Обратите внимание, что когда эта функция находит соответствующий символ, она возвращает не просто offset. Вместо этого она возвращает Some(offset). Some — это вариант или конструктор значения для типа Option. Его можно интерпретировать как функцию типа fn<T>(value: T) -> Option<T>. Соответственно, None — это также конструктор значения, только у него нет параметров. Его можно интерпретировать как функцию типа fn<T>() -> Option<T>.

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

fn main() {
    let file_name = "foobar.rs";
    match find(file_name, '.') {
        None => println!("Расширение файла не найдено."),
        Some(i) => println!("Расширение файла: {}", &file_name[i+1..]),
    }
}

Этот код использует сопоставление с образцом чтобы выполнить вариативный анализ для возвращаемого функцией find значения Option<usize>. На самом деле, вариативный анализ является единственным способом добраться до значения, сохраненного внутри Option<T>. Это означает, что вы, как разработчик, обязаны обработать случай, когда значение Option<T> равно None, а не Some(t).

Но подождите, как насчет unwrap, который мы до этого использовали? Там не было никакого вариативного анализа! Вместо этого, вариативный анализ был перемещен внутрь метода unwrap. Вы можете сделать это самостоятельно, если захотите:

enum Option<T> {
    None,
    Some(T),
}

impl<T> Option<T> {
    fn unwrap(self) -> T {
        match self {
            Option::Some(val) => val,
            Option::None =>
              panic!("called `Option::unwrap()` on a `None` value"),
        }
    }
}

Метод unwrap абстрагирует вариативный анализ. Это именно то, что делает unwrap удобным в использовании. К сожалению, panic! означает, что unwrap неудобно сочетать с другим кодом: это слон в посудной лавке.

Совмещение значений Option<T>

В предыдущем примере мы рассмотрели, как можно воспользоватся find для того, чтобы получить расширение имени файла. Конечно, не во всех именах файлов можно найти ., так что существует вероятность, что имя некоторого файла не имеет расширения. Эта возможность отсутствия интерпретируется на уровне типов через использование Option<T>. Другими словами, компилятор заставит нас рассмотреть возможность того, что расширение не существует. В нашем случае мы просто печатаем сообщение об этом.

Получение расширения имени файла — довольно распространенная операция, так что имеет смысл вынести код в отдельную функцию:

// Возвращает расширение заданного имени файла, а именно все символы,
// идущие за первым вхождением `.` в имя файла.
// Если в `file_name` нет ни одного вхождения `.`, возвращается `None`.
fn extension_explicit(file_name: &str) -> Option<&str> {
    match find(file_name, '.') {
        None => None,
        Some(i) => Some(&file_name[i+1..]),
    }
}

(Подсказка: не используйте этот код. Вместо этого используйте метод extension из стандартной библиотеки.)

Код выглядит простым, но его важный аспект заключается в том, что функция find заставляет нас рассмотреть вероятность отсутствия значения. Это хорошо, поскольку это означает, что компилятор не позволит нам случайно забыть о том варианте, когда в имени файла отсутствует расширение. С другой стороны, каждый раз выполнять явный вариативный анализ, подобно тому, как мы делали это в extension_explicit, может стать немного утомительным.

На самом деле, вариативный анализ в extension_explicit является очень распространенным паттерном: если Option<T> владеет определенным значением T, то выполнить его преобразование с помощью функции, а если нет — то просто вернуть None.

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

fn map<F, T, A>(option: Option<T>, f: F) -> Option<A> where F: FnOnce(T) -> A {
    match option {
        None => None,
        Some(value) => Some(f(value)),
    }
}

В действительности, map определен в стандартной библиотеке как метод Option<T>.

Вооружившись нашим новым комбинатором, мы можем переписать наш метод extension_explicit так, чтобы избавиться от вариативного анализа:

// Возвращает расширение заданного имени файла, а именно все символы,
// идущие за первым вхождением `.` в имя файла.
// Если в `file_name` нет ни одного вхождения `.`, возвращается `None`.
fn extension(file_name: &str) -> Option<&str> {
    find(file_name, '.').map(|i| &file_name[i+1..])
}

Есть еще одно поведение, которое можно часто встретить — это использование значения по-умолчанию в случае, когда значение Option равно None. К примеру, ваша программа может считать, что расширение файла равно rs в случае, если на самом деле оно отсутствует.

Легко представить, что этот случай вариативного анализа не специфичен только для расширений файлов — такой подход может работать с любым Option<T>:

fn unwrap_or<T>(option: Option<T>, default: T) -> T {
    match option {
        None => default,
        Some(value) => value,
    }
}

Хитрость только в том, что значение по-умолчанию должно иметь тот же тип, что и значение, которое может находится внутри Option<T>. Использование этого метода элементарно:

fn main() {
    assert_eq!(extension("foobar.csv").unwrap_or("rs"), "csv");
    assert_eq!(extension("foobar").unwrap_or("rs"), "rs");
}

(Обратите внимание, что unwrap_or объявлен как метод Option<T> в стандартной библиотеке, так что мы воспользовались им вместо функции, которую мы объявили ранее. Не забудьте также изучить более общий метод unwrap_or_else).

Существует еще один комбинатор, на который, как мы думаем, стоит обратить особое внимание: and_then. Он позволяет легко сочетать различные вычисления, которые допускают возможность отсутствия. Пример — большая часть кода в этом разделе, который связан с определением расширения заданного имени файла. Чтобы делать это, нам для начала необходимо узнать имя файла, которое как правило извлекается из файлового пути. Хотя большинство файловых путей содержат имя файла, подобное нельзя сказать обо всех файловых путях. Примером могут послужить пути ., .. или /.

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

fn file_path_ext_explicit(file_path: &str) -> Option<&str> {
    match file_name(file_path) {
        None => None,
        Some(name) => match extension(name) {
            None => None,
            Some(ext) => Some(ext),
        }
    }
}

fn file_name(file_path: &str) -> Option<&str> {
  unimplemented!() // опустим реализацию
}

Можно подумать, мы могли бы просто использовать комбинатор map, чтобы уменьшить вариативный анализ, но его тип не совсем подходит. Дело в том, что map принимает функцию, которая делает что-то только с внутренним значением. Результат такой функции всегда оборачивается в Some. Вместо этого, нам нужен метод, похожий map, но который позволяет вызывающему передать еще один Option. Его общая реализация даже проще, чем map:

fn and_then<F, T, A>(option: Option<T>, f: F) -> Option<A>
        where F: FnOnce(T) -> Option<A> {
    match option {
        None => None,
        Some(value) => f(value),
    }
}

Теперь мы можем переписать нашу функцию file_path_ext без явного вариативного анализа:

fn file_path_ext(file_path: &str) -> Option<&str> {
    file_name(file_path).and_then(extension)
}

Тип Option имеет много других комбинаторов определенных в стандартной библиотеке. Очень полезно просмотреть этот список и ознакомиться с доступными методами — они не раз помогут вам сократить количество вариативного анализа. Ознакомление с этими комбинаторами окупится еще и потому, что многие из них определены с аналогичной семантикой и для типа Result, о котором мы поговорим далее.

Комбинаторы делают использование типов вроде Option более удобным, ведь они сокращают явный вариативный анализ. Они также соответствуют требованиям сочетаемости, поскольку они позволяют вызывающему обрабатывать возможность отсутствия результата собственным способом. Такие методы, как unwrap, лишают этой возможности, ведь они будут паниковать в случае, когда Option<T> равен None.

Тип Result

Тип Result также определен в стандартной библиотеке:

enum Result<T, E> {
    Ok(T),
    Err(E),
}

Тип Result — это продвинутая версия Option. Вместо того, чтобы выражать возможность отсутствия, как это делает Option, Result выражает возможность ошибки. Как правило, ошибки необходимы для объяснения того, почему результат определенного вычисления не был получен. Строго говоря, это более общая форма Option. Рассмотрим следующий псевдоним типа, который во всех смыслах семантически эквивалентен реальному Option<T>:

type Option<T> = Result<T, ()>;

Здесь второй параметр типа Result фиксируется и определяется через () (произносится как «unit» или «пустой кортеж»). Тип () имеет ровно одно значение — (). (Да, это тип и значение этого типа, которые выглядят одинаково!)

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

Подобно Option, тип Result имеет метод unwrap, определенный в стандартной библиотеке. Давайте объявим его самостоятельно:

impl<T, E: ::std::fmt::Debug> Result<T, E> {
    fn unwrap(self) -> T {
        match self {
            Result::Ok(val) => val,
            Result::Err(err) =>
              panic!("called `Result::unwrap()` on an `Err` value: {:?}", err),
        }
    }
}

Это фактически то же самое, что и определение Option::unwrap, за исключением того, что мы добавили значение ошибки в сообщение panic!. Это делает отладку проще, но это вынуждает нас требовать от типа-параметра E (который представляет наш тип ошибки) реализации Debug. Поскольку подавляющее большинство типов должны реализовывать Debug, обычно на практике такое ограничение не мешает. (Реализация Debug для некоторого типа просто означает, что существует разумный способ печати удобочитаемого описания значения этого типа.)

Окей, давайте перейдем к примеру.

Преобразование строки в число

Стандартная библиотека Rust позволяет элементарно преобразовывать строки в целые числа. На самом деле это настолько просто, что возникает соблазн написать что-то вроде:

fn double_number(number_str: &str) -> i32 {
    2 * number_str.parse::<i32>().unwrap()
}

fn main() {
    let n: i32 = double_number("10");
    assert_eq!(n, 20);
}

Здесь вы должны быть скептически настроены по-поводу вызова unwrap. Если строку нельзя распарсить как число, вы получите панику:

thread '<main>' panicked at 'called `Result::unwrap()` on an `Err` value: ParseIntError { kind: InvalidDigit }', /home/rustbuild/src/rust-buildbot/slave/beta-dist-rustc-linux/build/src/libcore/result.rs:729

Это довольно неприятно, и если бы подобное произошло в используемой вами библиотеке, вы могли бы небезосновательно разгневаться. Так что нам стоит попытаться обработать ошибку в нашей функции, и пусть вызывающий сам решит что с этим делать. Это означает необходимость изменения типа, который возвращается double_number. Но на какой? Чтобы понять это, необходимо посмотреть на сигнатуру метода parse из стандартной библиотеки:

impl str {
    fn parse<F: FromStr>(&self) -> Result<F, F::Err>;
}

Хмм. По крайней мере мы знаем, что должны использовать Result. Вполне возможно, что метод мог возвращать Option. В конце концов, строка либо парсится как число, либо нет, не так ли? Это, конечно, разумный путь, но внутренняя реализация знает почему строка не распарсилась как целое число. (Это может быть пустая строка, или неправильные цифры, слишком большая или слишком маленькая длина и т.д.) Таким образом, использование Result имеет смысл, ведь мы хотим предоставить больше информации, чем просто «отсутствие». Мы хотим сказать, почему преобразование не удалось. Вам стоит рассуждать похожим образом, когда вы сталкиваетесь с выбором между Option и Result. Если вы можете предоставить подробную информацию об ошибке, то вам, вероятно, следует это сделать. (Позже мы поговорим об этом подробнее.)

Хорошо, но как мы запишем наш тип возвращаемого значения? Метод parse является обобщенным (generic) для всех различных типов чисел из стандартной библиотеки. Мы могли бы (и, вероятно, должны) также сделать нашу функцию обобщенной, но давайте пока остановимся на конкретной реализации. Нас интересует только тип i32, так что нам стоит найти его реализацию FromStr (выполните поиск в вашем браузере по строке «FromStr») и посмотреть на его ассоциированный тип Err. Мы делаем это чтобы определить конкретный тип ошибки. В данном случае, это std::num::ParseIntError. Наконец, мы можем переписать нашу функцию:

use std::num::ParseIntError;

fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
    match number_str.parse::<i32>() {
        Ok(n) => Ok(2 * n),
        Err(err) => Err(err),
    }
}

fn main() {
    match double_number("10") {
        Ok(n) => assert_eq!(n, 20),
        Err(err) => println!("Error: {:?}", err),
    }
}

Неплохо, но нам пришлось написать гораздо больше кода! И нас опять раздражает вариативный анализ.

Комбинаторы спешат на помощь! Подобно Option, Result имеет много комбинаторов, определенных в качестве методов. Существует большой список комбинаторов, общих между Result и Option. И map входит в этот список:

use std::num::ParseIntError;

fn double_number(number_str: &str) -> Result<i32, ParseIntError> {
    number_str.parse::<i32>().map(|n| 2 * n)
}

fn main() {
    match double_number("10") {
        Ok(n) => assert_eq!(n, 20),
        Err(err) => println!("Error: {:?}", err),
    }
}

Все ожидаемые методы реализованы для Result, включая unwrap_or и and_then. Кроме того, поскольку Result имеет второй параметр типа, существуют комбинаторы, которые влияют только на значение ошибки, такие как map_err (аналог map) и or_else (аналог and_then).

Создание псевдонима типа Result

В стандартной библиотеке можно часто увидеть типы вроде Result<i32>. Но постойте, ведь мы определили Result с двумя параметрами типа. Как мы можем обойти это, указывая только один из них? Ответ заключается в определении псевдонима типа Result, который фиксирует один из параметров конкретным типом. Обычно фиксируется тип ошибки. Например, наш предыдущий пример с преобразованием строк в числа можно переписать так:

use std::num::ParseIntError;
use std::result;

type Result<T> = result::Result<T, ParseIntError>;

fn double_number(number_str: &str) -> Result<i32> {
    unimplemented!();
}

Зачем мы это делаем? Что ж, если у нас есть много функций, которые могут вернуть ParseIntError, то гораздо удобнее определить псевдоним, который всегда использует ParseIntError, так что мы не будем повторяться все время.

Самый заметный случай использования такого подхода в стандартной библиотеке — псевдоним io::Result. Как правило, достаточно писать io::Result<T>, чтобы было понятно, что вы используете псевдоним типа из модуля io, а не обычное определение из std::result. (Этот подход также используется для fmt::Result)

Короткое отступление: unwrap — не обязательно зло

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

Тем не менее, unwrap все-таки можно использовать разумно. Факторы, которые оправдывают использование unwrap, являются несколько туманными, и разумные люди могут со мной не согласиться. Я кратко изложу свое мнение по этому вопросу:

  • Примеры и «грязный» код. Когда вы пишете просто пример или быстрый скрипт, обработка ошибок просто не требуется. Для подобных случаев трудно найти что-либо удобнее чем unwrap, так что здесь его использование очень привлекательно.
  • Паника указывает на ошибку в программе. Если логика вашего кода должна предотвращать определенное поведение (скажем, получение элемента из пустого стека), то использование panic также допустимо. Дело в том, что в этом случае паника будет сообщать о баге в вашей программе. Это может происходить явно, например от неудачного вызова assert!, или происходить потому, что индекс по массиву находится за пределами выделенной памяти.

Вероятно, это не исчерпывающий список. Кроме того, при использовании Option зачастую лучше использовать метод expect. Этот метод делает ровно то же, что и unwrap, за исключением того, что в случае паники напечатает ваше сообщение. Это позволит лучше понять причину ошибки, ведь будет показано конкретное сообщение, а не просто «called unwrap on a None value».

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

Теперь, когда мы рассмотрели основы обработки ошибок в Rust и разобрались с unwrap, давайте подробнее изучим стандартную библиотеку.

Работа с несколькими типами ошибок

До этого момента мы расматривали обработку ошибок только для случаев, когда все сводилось либо только к Option<T>, либо только к Result<T, SomeError>. Но что делать, когда у вас есть и Option, и Result? Или если у вас есть Result<T, Error1> и Result<T, Error2>? Наша следующуя задача — обработка композиции различных типов ошибок, и это будет главной темой на протяжении всей этой статьи.

Совмещение Option и Result

Пока что мы говорили о комбинаторах, определенных для Option, и комбинаторах, определенных для Result. Эти комбинаторы можно использовать для того, чтобы сочетать результаты различных вычислений, не делая подробного вариативного анализа.

Конечно, в реальном коде все происходит не так гладко. Иногда у вас есть сочетания типов Option и Result. Должны ли мы прибегать к явному вариативному анализу, или можно продолжить использовать комбинаторы?

Давайте на время вернемся к одному из первых примеров в этой статье:

use std::env;

fn main() {
    let mut argv = env::args();
    let arg: String = argv.nth(1).unwrap(); // ошибка 1
    let n: i32 = arg.parse().unwrap(); // ошибка 2
    println!("{}", 2 * n);
}

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

Ньюанс заключается в том, что argv.nth(1) возвращает Option, в то время как arg.parse() возвращает Result. Они не могут быть скомпонованы непосредственно. Когда вы сталкиваетесь одновременно с Option и Result, обычно наилучшее решение — преобразовать Option в Result. В нашем случае, отсутствие параметра командной строки (из env::args()) означает, что пользователь не правильно вызвал программу. Мы могли бы просто использовать String для описания ошибки. Давайте попробуем:

use std::env;

fn double_arg(mut argv: env::Args) -> Result<i32, String> {
    argv.nth(1)
        .ok_or("Please give at least one argument".to_owned())
        .and_then(|arg| arg.parse::<i32>().map_err(|err| err.to_string()))
}

fn main() {
    match double_arg(env::args()) {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Error: {}", err),
    }
}

Раcсмотрим пару новых моментов на этом примере. Во-первых, использование комбинатора Option::ok_or. Это один из способов преобразования Option в Result. Такое преобразование требует явного определения ошибки, которую необходимо вернуть в случае, когда значение Option равно None. Как и для всех комбинаторов, которые мы рассматривали, его объявление очень простое:

fn ok_or<T, E>(option: Option<T>, err: E) -> Result<T, E> {
    match option {
        Some(val) => Ok(val),
        None => Err(err),
    }
}

Второй новый комбинатор, который мы использовали — Result::map_err. Это то же самое, что и Result::map, за исключением того, функция применяется к ошибке внутри Result. Если значение Result равно Оk(...), то оно возвращается без изменений.

Мы используем map_err, потому что нам необходимо привести все ошибки к одинаковому типу (из-за нашего использования and_then). Поскольку мы решили преобразовывать Option<String> (из argv.nth(1)) в Result<String, String>, мы также обязаны преобразовывать ParseIntError из arg.parse() в String.

Ограничения комбинаторов

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

Давайте начнем с простого. Поставим задачу открыть файл, прочесть все его содержимое и преобразовать это содержимое в число. После этого нужно будет умножить значение на 2 и распечатать результат.

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

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> i32 {
    let mut file = File::open(file_path).unwrap(); // ошибка 1
    let mut contents = String::new();
    file.read_to_string(&mut contents).unwrap();   // ошибка 2
    let n: i32 = contents.trim().parse().unwrap(); // ошибка 3
    2 * n
}

fn main() {
    let doubled = file_double("foobar");
    println!("{}", doubled);
}

(Замечание: Мы используем AsRef по тем же причинам, почему он используется в std::fs::File::open. Это позволяет удобно использовать любой тип строки в качестве пути к файлу.)

У нас есть три потенциальные ошибки, которые могут возникнуть:

  1. Проблема при открытии файла.
  2. Проблема при чтении данных из файла.
  3. Проблема при преобразовании данных в число.

Первые две проблемы определяются типом std::io::Error. Мы знаем это из типа возвращаемого значения методов std::fs::File::open и std::io::Read::read_to_string. (Обратите внимание, что они оба используют концепцию с псевдонимом типа Result, описанную ранее. Если вы кликните на тип Result, вы увидите псевдоним типа, и следовательно, лежащий в основе тип io::Error.) Третья проблема определяется типом std::num::ParseIntError. Кстати, тип io::Error часто используется по всей стандартной библиотеке. Вы будете видеть его снова и снова.

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

Первое, что мы должны решить: какой из типов использовать: Option или Result? Мы, конечно, могли бы с легкостью использовать Option. Если какая-либо из трех ошибок происходит, мы могли бы просто вернуть None. Это будет работать, и это лучше, чем просто паниковать, но мы можем сделать гораздо лучше. Вместо этого, мы будем сообщать некоторые детали о возникшей проблеме. Поскольку мы хотим выразить возможность ошибки, мы должны использовать Result<i32, E>. Но каким должен быть тип E? Поскольку может возникнуть два разных типа ошибок, мы должны преобразовать их к общему типу. Одним из таких типов является String. Давайте посмотрим, как это отразится на нашем коде:

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    File::open(file_path)
         .map_err(|err| err.to_string())
         .and_then(|mut file| {
              let mut contents = String::new();
              file.read_to_string(&mut contents)
                  .map_err(|err| err.to_string())
                  .map(|_| contents)
         })
         .and_then(|contents| {
              contents.trim().parse::<i32>()
                      .map_err(|err| err.to_string())
         })
         .map(|n| 2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Ошибка: {}", err),
    }
}

Выглядит немного запутанно. Может потребоваться довольно много практики, прежде вы сможете писать такое. Написание кода в таком стиле называется следованием за типом. Когда мы изменили тип возвращаемого значения file_double на Result<i32, String>, нам пришлось начать подбирать правильные комбинатороы. В данном случае мы использовали только три различных комбинатора: and_then, map и map_err.

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

Комбинатор map используется, чтобы применить функцию к значению Ok(...) типа Result. Например, в самом последнем вызове, map умножает значение Ok(...) (типа i32) на 2. Если ошибка произошла до этого момента, эта операция была бы пропущена. Это следует из определения map.

Комбинатор map_err — это уловка, которая позволяют всему этому заработать. Этот комбинатор, такой же, как и map, за исключением того, что применяет функцию к Err(...) значению Result. В данном случае мы хотим привести все наши ошибки к одному типу — String. Поскольку как io::Error, так и num::ParseIntError реализуют ToString, мы можем вызвать метод to_string, чтобы выполнить преобразование.

Не смотря на все сказанное, код по-прежнему выглядит запутанным. Мастерство использования комбинаторов является важным, но у них есть свои недостатки. Давайте попробуем другой подход: преждевременный возврат.

Преждевременный return

Давайте возьмем код из предыдущего раздела и перепишем его с применением раннего возврата. Ранний return позволяет выйти из функции досрочно. Мы не можем выполнить return для file_double внутри замыкания, поэтому нам необходимо вернуться к явному вариативному анализу.

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    let mut file = match File::open(file_path) {
        Ok(file) => file,
        Err(err) => return Err(err.to_string()),
    };
    let mut contents = String::new();
    if let Err(err) = file.read_to_string(&mut contents) {
        return Err(err.to_string());
    }
    let n: i32 = match contents.trim().parse() {
        Ok(n) => n,
        Err(err) => return Err(err.to_string()),
    };
    Ok(2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Ошибка: {}", err),
    }
}

Кто-то может обосновано не согласиться с тем, что этот код лучше, чем тот, который использует комбинаторы, но если вы не знакомы с комбинаторами, на мой взгляд, этот код будет выглядеть проще. Он выполняет явный вариативный анализ с помощью match и if let. Если происходит ошибка, мы просто прекращаем выполнение функции и возвращаем ошибку (после преобразования в строку).

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

Макрос try!

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

Вот упрощенное определение макроса `try!:

macro_rules! try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(err),
    });
}

(Реальное определение выглядит немного сложнее. Мы обсудим это далее).

Использование макроса try! может очень легко упростить наш последний пример. Поскольку он выполняет анализ вариантов и досрочной возврат из функции, мы получаем более плотный код, который легче читать:

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
    let n = try!(contents.trim().parse::<i32>().map_err(|e| e.to_string()));
    Ok(2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Ошибка: {}", err),
    }
}

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

Объявление собственного типа ошибки

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

Использование String в том стиле, в котором мы использовали его в предыдущих примерах удобно потому, что достаточно легко конвертировать любые ошибки в строки, или даже создавать свои собственные ошибки на ходу. Тем не менее, использование типа String для ошибок имеет некоторые недостатки.

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

Второй и более важный недостаток заключается в том, что использование String чревато потерей информации. Другими словами, если все ошибки будут преобразованы в строки, то когда мы будем возвращать их вызывающей стороне, они не будут иметь никакого смысла. Единственное разумное, что вызывающая сторона может сделать с ошибкой типа String — это показать ее пользователю. Безусловно, можно проверить строку по значению, чтобы определить тип ошибки, но такой подход не может похвастаться надежностью. (Правда, в гораздо большей степени это недостаток для библиотек, чем для конечных приложений).

Например, тип io::Error включает в себя тип io::ErrorKind, который является структурированными данными, представляющими то, что пошло не так во время выполнения операции ввода-вывода. Это важно, поскольку может возникнуть необходимость по-разному реагировать на различные причины ошибки. (Например, ошибка BrokenPipe может изящно завершать программу, в то время как ошибка NotFound будет завершать программу с кодом ошибки и показывать соответствующее сообщение пользователю.) Благодаря io::ErrorKind, вызывающая сторона может исследовать тип ошибки с помощью вариативного анализа, и это значительно лучше попытки вычленить детали об ошибке из String.

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

Идеальным способом представления одного варианта из многих является определение нашего собственного типа-суммы с помощью enum. В нашем случае, ошибка представляет собой либо io::Error, либо num::ParseIntError, из чего естественным образом вытекает определение:

use std::io;
use std::num;

// Мы реализуем `Debug` поскольку, по всей видимости, все типы должны реализовывать `Debug`.
// Это дает нам возможность получить адекватное и читаемое описание значения CliError
#[derive(Debug)]
enum CliError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

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

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, CliError> {
    let mut file = try!(File::open(file_path).map_err(CliError::Io));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(CliError::Io));
    let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse));
    Ok(2 * n)
}

fn main() {
    match file_double("foobar") {
        Ok(n) => println!("{}", n),
        Err(err) => println!("Ошибка: {:?}", err),
    }
}

Единственное изменение здесь — замена вызова map_err(|e| e.to_string()) (который преобразовывал ошибки в строки) на map_err(CliError::Io) или map_err(CliError::Parse). Теперь вызывающая сторона определяет уровень детализации сообщения об ошибке для конечного пользователя. В действительности, использование String как типа ошибки лишает вызывающего возможности выбора, в то время использование собственного типа enum, на подобие CliError, дает вызывающему тот же уровень удобства, который был ранее, и кроме этого структурированные данные, описывающие ошибку.

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

Типажи из стандартной библиотеки, используемые для обработки ошибок

Стандартная библиотека определяет два встроенных типажа, полезных для обработки ошибок std::error::Error и std::convert::From. И если Error разработан специально для создания общего описания ошибки, то типаж From играет широкую роль в преобразовании значений между различными типами.

Типаж Error

Типаж Error объявлен в стандартной библиотеке:

use std::fmt::{Debug, Display};

trait Error: Debug + Display {
  /// A short description of the error.
  fn description(&self) -> &str;

  /// The lower level cause of this error, if any.
  fn cause(&self) -> Option<&Error> { None }
}

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

  • Получать строковое представление ошибки для разработчика (Debug).
  • Получать понятное для пользователя представление ошибки (Display).
  • Получать краткое описание ошибки (метод description).
  • Изучать по цепочке первопричину ошибки, если она существует (метод cause).

Первые две возможности возникают в результате того, что типаж Error требует в свою очередь реализации типажей Debug и Display. Последние два факта исходят из двух методов, определенных в самом Error. Мощь Еrror заключается в том, что все существующие типы ошибок его реализуют, что в свою очередь означает что любые ошибки могут быть сохранены как типажи-объекты (trait object). Обычно это выглядит как Box<Error>, либо &Error. Например, метод cause возвращает &Error, который как раз является типажом-объектом. Позже мы вернемся к применению Error как типажа-объекта.

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

use std::io;
use std::num;

// Мы реализуем `Debug` поскольку, по всей видимости, все типы должны реализовывать `Debug`.
// Это дает нам возможность получить адекватное и читаемое описание значения CliError
#[derive(Debug)]
enum CliError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

Данный тип ошибки отражает возможность возникновения двух других типов ошибок: ошибка работы с IО или ошибка преобразования строки в число. Определение ошибки может отражать столько других видов ошибок, сколько необходимо, за счет добавления новых вариантов в объявлении enum.

Реализация Error довольно прямолинейна и главным образом состоит из явного анализа вариантов:

use std::error;
use std::fmt;

impl fmt::Display for CliError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match *self {
            // Оба изначальных типа ошибок уже реализуют `Display`,
            // так что мы можем использовать их реализации
            CliError::Io(ref err) => write!(f, "IO error: {}", err),
            CliError::Parse(ref err) => write!(f, "Parse error: {}", err),
        }
    }
}

impl error::Error for CliError {
    fn description(&self) -> &str {
        // Оба изначальных типа ошибок уже реализуют `Error`,
        // так что мы можем использовать их реализацией
        match *self {
            CliError::Io(ref err) => err.description(),
            CliError::Parse(ref err) => err.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match *self {
            // В обоих случаях просходит неявное преобразование значения `err`
            // из конкретного типа (`&io::Error` или `&num::ParseIntError`)
            // в типаж-обьект `&Error`. Это работает потому что оба типа реализуют `Error`.
            CliError::Io(ref err) => Some(err),
            CliError::Parse(ref err) => Some(err),
        }
    }
}

Хочется отметить, что это очень типичная реализация Error: реализация методов description и cause в соответствии с каждым возможным видом ошибки.

Типаж From

Типаж std::convert::From объявлен в стандартной библиотеке:

trait From<T> {
    fn from(T) -> Self;
}

Очень просто, не правда ли? Типаж From чрезвычайно полезен, поскольку создает общий подход для преобразования из определенного типа Т в какой-то другой тип (в данном случае, «другим типом» является тип, реализующий данный типаж, или Self). Самое важное в типаже From — множество его реализаций, предоставляемых стандартной библиотекой.

Вот несколько простых примеров, демонстрирующих работу From:

let string: String = From::from("foo");
let bytes: Vec<u8> = From::from("foo");
let cow: ::std::borrow::Cow<str> = From::from("foo");

Итак, From полезен для выполнения преобразований между строками. Но как насчет ошибок? Оказывается, существует одна важная реализация:

impl<'a, E: Error + 'a> From<E> for Box<Error + 'a>

Эта реализация говорит, что любой тип, который реализует Error, можно конвертировать в типаж-объект Box<Error>. Выглядит не слишком впечатляюще, но это очень полезно в общем контексте.

Помните те две ошибки, с которыми мы имели дело ранее, а именно, io::Error and num::ParseIntError? Поскольку обе они реализуют Error, они также работают с From:

use std::error::Error;
use std::fs;
use std::io;
use std::num;

// Получаем значения ошибок
let io_err: io::Error = io::Error::last_os_error();
let parse_err: num::ParseIntError = "not a number".parse::<i32>().unwrap_err();

// Собственно, конвертация
let err1: Box<Error> = From::from(io_err);
let err2: Box<Error> = From::from(parse_err);

Здесь нужно разобрать очень важный паттерн. Переменные err1 и err2 имеют одинаковый тип — типаж-объект. Это означает, что их реальные типы скрыты от компилятора, так что по факту он рассматривает err1 и err2 как одинаковые сущности. Кроме того, мы создали err1 и err2, используя один и тот же вызов функции — From::from. Мы можем так делать, поскольку функция From::from перегружена по ее аргументу и возвращаемому типу.

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

Настало время вернуться к нашему старому другу — макросу try!.

Настоящий макрос try!

До этого мы привели такое определение try!:

macro_rules! try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(err),
    });
}

Но это не настоящее определение. Реальное определение можно найти в стандартной библиотеке:

macro_rules! try {
    ($e:expr) => (match $e {
        Ok(val) => val,
        Err(err) => return Err(::std::convert::From::from(err)),
    });
}

Здесь есть одно маленькое, но очень важное изменение: значение ошибки пропускается через вызов From::from. Это делает макрос try! очень мощным инструментом, поскольку он дает нам возможность бесплатно выполнять автоматическое преобразование типов.

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

use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, String> {
    let mut file = try!(File::open(file_path).map_err(|e| e.to_string()));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(|e| e.to_string()));
    let n = try!(contents.trim().parse::<i32>().map_err(|e| e.to_string()));
    Ok(2 * n)
}

Ранее мы говорили, что мы можем избавиться от вызовов map_err. На самом деле, все что мы должны для этого сделать — это найти тип, который работает с From. Как мы увидели в предыдущем разделе, From имеет реализацию, которая позволяет преобразовать любой тип ошибки в Box<Error>:

use std::error::Error;
use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, Box<Error>> {
    let mut file = try!(File::open(file_path));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents));
    let n = try!(contents.trim().parse::<i32>());
    Ok(2 * n)
}

Мы уже очень близки к идеальной обработке ошибок. Наш код имеет очень мало накладных расходов из-за обработки ошибок, ведь макрос try! инкапсулирует сразу три вещи:

  1. Вариативный анализ.
  2. Поток выполнения.
  3. Преобразование типов ошибок.

Когда все эти три вещи объединены вместе, мы получаем код, который не обременен комбинаторами, вызовами unwrap или постоянным анализом вариантов.

Но осталась одна маленькая деталь: тип Box<Error> не несет никакой информации. Если мы возвращаем Box<Error> вызывающей стороне, нет никакой возможности (легко) узнать базовый тип ошибки. Ситуация, конечно, лучше, чем со String, посольку появилась возможность вызывать методы, вроде description или cause, но ограничение остается: Box<Error> не предоставляет никакой информации о сути ошибки. (Замечание: Это не совсем верно, поскольку в Rust есть инструменты рефлексии во время выполнения, которые полезны при некоторых сценариях, но их рассмотрение выходит за рамки этой статьи).

Настало время вернуться к нашему собственному типу CliError и связать все в одно целое.

Совмещение собственных типов ошибок

В последнем разделе мы рассмотрели реальный макрос try! и то, как он выполняет автоматическое преобразование значений ошибок с помощью вызова From::from. В нашем случае мы конвертировали ошибки в Box<Error>, который работает, но его значение скрыто для вызывающей стороны.

Чтобы исправить это, мы используем средство, с которым мы уже знакомы: создание собственного типа ошибки. Давайте вспомним код, который считывает содержимое файла и преобразует его в целое число:

use std::fs::File;
use std::io::{self, Read};
use std::num;
use std::path::Path;

// Мы реализуем `Debug` поскольку, по всей видимости, все типы должны реализовывать `Debug`.
// Это дает нам возможность получить адекватное и читаемое описание значения CliError
#[derive(Debug)]
enum CliError {
    Io(io::Error),
    Parse(num::ParseIntError),
}

fn file_double_verbose<P: AsRef<Path>>(file_path: P) -> Result<i32, CliError> {
    let mut file = try!(File::open(file_path).map_err(CliError::Io));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents).map_err(CliError::Io));
    let n: i32 = try!(contents.trim().parse().map_err(CliError::Parse));
    Ok(2 * n)
}

Обратите внимание, что здесь у нас еще остались вызовы map_err. Почему? Вспомните определения try! и From. Проблема в том, что не существует такой реализации From, которая позволяет конвертировать типы ошибок io::Error и num::ParseIntError в наш собственный тип CliError. Но мы можем легко это исправить! Поскольку мы определили тип CliError, мы можем также реализовать для него типаж From:

use std::io;
use std::num;

impl From<io::Error> for CliError {
    fn from(err: io::Error) -> CliError {
        CliError::Io(err)
    }
}

impl From<num::ParseIntError> for CliError {
    fn from(err: num::ParseIntError) -> CliError {
        CliError::Parse(err)
    }
}

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

Наконец, мы можем переписать file_double:


use std::fs::File;
use std::io::Read;
use std::path::Path;

fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, CliError> {
    let mut file = try!(File::open(file_path));
    let mut contents = String::new();
    try!(file.read_to_string(&mut contents));
    let n: i32 = try!(contents.trim().parse());
    Ok(2 * n)
}

Единственное, что мы сделали — это удалили вызовы map_err. Они нам больше не нужны, поскольку макрос try! выполняет From::from над значениями ошибок. И это работает, поскольку мы предоставили реализации From для всех типов ошибок, которые могут возникнуть.

Если бы мы изменили нашу функцию file_double таким образом, чтобы она начала выполнять какие-то другие операции, например, преобразовать строку в число с плавающей точкой, то мы должны были бы добавить новый вариант к нашему типу ошибок:

use std::io;
use std::num;

enum CliError {
    Io(io::Error),
    ParseInt(num::ParseIntError),
    ParseFloat(num::ParseFloatError),
}

И добавить новую реализацию для From:


use std::num;

impl From<num::ParseFloatError> for CliError {
    fn from(err: num::ParseFloatError) -> CliError {
        CliError::ParseFloat(err)
    }
}

Вот и все!

Рекомендации для авторов библиотек

Если в вашей библиотеке могут возникать специфические ошибки, то вы наверняка должны определить для них свой собственный тип. На ваше усмотрение вы можете сделать его внутреннее представление публичным (как ErrorKind), или оставить его скрытым (подобно ParseIntError). Независимо от того, что вы предпримете, считается хорошим тоном обеспечить по крайней мере некоторую информацию об ошибке помимо ее строкового представления. Но, конечно, все зависит от конкретных случаев использования.

Как минимум, вы скорее всего должны реализовать типаж Error. Это даст пользователям вашей библиотеки некоторую минимальную гибкость при совмещении ошибок. Реализация типажа Error также означает, что пользователям гарантируется возможность получения строкового представления ошибки (это следует из необходимости реализации fmt::Debug и fmt::Display).

Кроме того, может быть полезным реализовать From для ваших типов ошибок. Это позволит вам (как автору библиотеки) и вашим пользователям совмещать более детальные ошибки. Например, csv::Error реализует From для io::Error и byteorder::Error.

Наконец, на свое усмотрение, вы также можете определить псевдоним типа Result, особенно, если в вашей библиотеке определен только один тип ошибки. Такой подход используется в стандартной библиотеке для io::Result и fmt::Result.

Заключение

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

  • Если вы пишете короткий пример кода, который может быть перегружен обработкой ошибок, это, вероятно, отличная возможность использовать unwrap (будь-то Result::unwrap, Option::unwrap или Option::expect). Те, для кого предназначен пример, должны осознавать, что необходимо реализовать надлежащую обработку ошибок. (Если нет, отправляйте их сюда!)
  • Если вы пишете одноразовую программу, также не зазорно использовать unwrap. Но будьте внимательны: если ваш код попадет в чужие руки, не удивляйтесь, если кто-то будет расстроен из-за скудных сообщений об ошибках!
  • Если вы пишете одноразовый код, но вам все-равно стыдно из-за использования unwrap, воспользуйтесь либо String в качестве типа ошибки, либо Box<Error + Send + Sync> (из-за доступных реализаций From.)
  • В остальных случаях, определяйте свои собственные типы ошибок с соответствующими реализациями From и Error, делая использование try! более удобным.
  • Если вы пишете библиотеку и ваш код может выдавать ошибки, определите ваш собственный тип ошибки и реализуйте типаж std::error::Error. Там, где это уместно, реализуйте From, чтобы вам и вашим пользователям было легче с ними работать. (Из-за правил когерентности в Rust, пользователи вашей библиотеки не смогут реализовать From для ваших ошибок, поэтому это должна сделать ваша библиотека.)
  • Изучите комбинаторы, определенные для Option и Result. Писать код, пользуясь только ними может быть немного утомительно, но я лично нашел для себя хороший баланс между использованием try! и комбинаторами (and_then, map и unwrap_or — мои любимые).

Эта статья была подготовлена в рамках перевода на русский язык официального руководства «The Rust Programming Language». Переводы остальных глав этой книги можно найти здесь. Так же, если у вас есть любые вопросы, связанные с Rust, вы можете задать их в чате русскоязычного сообщества Rust.

I am a complete beginner (following this course actually) regarding Rust language and i was wondering if it was possible to create an app for Windows involving a mqtt client.

I created my project using cargo new testmqtt --bin,

my toml file is

[package]
name = "testmqtt"
version = "0.1.0"
authors = ["Pierre"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
mosquitto-client = "0.1.5"

Main.rs file is exactly the first one found here.

extern crate mosquitto_client as mosq;
use mosq::Mosquitto;

fn main() {
    let m = Mosquitto::new("test");

    m.will_set("test/will",b"finished!",0,false).expect("can't set will");

    m.connect("localhost",1883).expect("can't connect");
    let bonzo = m.subscribe("bonzo/#",0).expect("can't subscribe to bonzo");
    let frodo = m.subscribe("frodo/#",0).expect("can't subscribe to frodo");

    // not interested in any retained messages!
    let mut mc = m.callbacks(());
    mc.on_message(|_,msg| {
        if ! msg.retained() {
            if bonzo.matches(&msg) {
                println!("bonzo {:?}",msg);
            } else
            if frodo.matches(&msg) {
                println!("frodo {:?}",msg);
                m.disconnect().unwrap();
            }
        }
    });

    m.loop_forever(200).expect("broken loop");
}

When doing cargo run, i do have an error saying more or less that i have to include mosquitto.lib file.

Compiling testmqtt v0.1.0 (C:UsersPierrerusttestmqtt)
    Finished dev [unoptimized + debuginfo] target(s) in 3.43s
     Running `targetdebugtestmqtt.exe`
Hello, world!
PS C:UsersPierrerusttestmqtt> cargo run
    Updating crates.io index
   Compiling mosquitto-client v0.1.5
   Compiling testmqtt v0.1.0 (C:UsersPierrerusttestmqtt)
error: linking with `link.exe` failed: exit code: 1181
  |
  = note: "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.23.28105\bin\HostX64\x64\link.exe" "/NOLOGO" "/NXCOMPAT" "/LIBPATH:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.18yxopwcqksqllf0.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.26hriqf9eoqoz70e.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.287dmq688xsz3isv.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2e77zj76zbvh065j.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2huuzosvc51r1ocl.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2o9r9r2t2clr39wq.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2wggiqwux76jad1h.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.3mqzooten3ugyse9.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.3vqvdeaqidai2p26.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4fnmrub2ky4biwf5.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4tdiuzs0kqadbi75.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4u40iyf9g9kmiphf.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.51m4wneyq731nq60.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.5d67na1jjhizscb4.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.ap2kea3xxb47i5p.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.h5xgbt8abre0rtw.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.vlg3p2hoy45m5m6.rcgu.o" "/OUT:C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.exe" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.49ivjbnnhficmjo4.rcgu.o" "/OPT:REF,NOICF" "/DEBUG" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\intrinsic.natvis" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\liballoc.natvis" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\libcore.natvis" "/LIBPATH:C:\Users\Pierre\rust\testmqtt\target\debug\deps" "/LIBPATH:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\libmosquitto_client-23967bfdaa3a5433.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libstd-8864852919b3dde3.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libpanic_unwind-60bab00b06422126.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libbacktrace-e90b3ab99b608a07.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_demangle-d9b7b1604d471c6c.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libhashbrown-a439eac7fda93b7a.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_alloc-058c975bf38e4686.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libunwind-711d56157cf28645.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcfg_if-d802c196c150a787.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liblibc-7147008fc56d32b8.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liballoc-57b2ee5c835455f8.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_core-6391a360e3eeafba.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcore-6c8df881cdc2afb2.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcompiler_builtins-f998976453a15b70.rlib" "mosquitto.lib" "c.lib" "advapi32.lib" "ws2_32.lib" "userenv.lib" "msvcrt.lib"
  = note: Non-UTF-8 output: LINK : fatal error LNK1181: impossible d'ouvrir le fichier en entrxe9e 'mosquitto.lib'rn

error: aborting due to previous error

error: Could not compile `testmqtt`.

To learn more, run the command again with --verbose.

Here is the verbose ouput

To learn more, run the command again with —verbose.

PS C:UsersPierrerusttestmqtt> cargo run --verbose
       Fresh mosquitto-client v0.1.5
   Compiling testmqtt v0.1.0 (C:UsersPierrerusttestmqtt)
     Running `rustc --edition=2018 --crate-name testmqtt srcmain.rs --color always --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=e2a79a549b8dacef -C extra-filename=-e2a79a549b8dacef --out-dir C:UsersPierrerusttestmqtttargetdebugdeps -C incremental=C:UsersPierrerusttestmqtttargetdebugincremental -L dependency=C:UsersPierrerusttestmqtttargetdebugdeps --extern mosquitto_client=C:UsersPierrerusttestmqtttargetdebugdepslibmosquitto_client-23967bfdaa3a5433.rlib`error: linking with `link.exe` failed: exit code: 1181
  |
  = note: "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Tools\MSVC\14.23.28105\bin\HostX64\x64\link.exe" "/NOLOGO" "/NXCOMPAT" "/LIBPATH:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.18yxopwcqksqllf0.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.26hriqf9eoqoz70e.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.287dmq688xsz3isv.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2e77zj76zbvh065j.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2huuzosvc51r1ocl.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2o9r9r2t2clr39wq.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.2wggiqwux76jad1h.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.3mqzooten3ugyse9.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.3vqvdeaqidai2p26.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4fnmrub2ky4biwf5.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4tdiuzs0kqadbi75.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.4u40iyf9g9kmiphf.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.51m4wneyq731nq60.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.5d67na1jjhizscb4.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.ap2kea3xxb47i5p.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.h5xgbt8abre0rtw.rcgu.o" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.vlg3p2hoy45m5m6.rcgu.o" "/OUT:C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.exe" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\testmqtt-e2a79a549b8dacef.49ivjbnnhficmjo4.rcgu.o" "/OPT:REF,NOICF" "/DEBUG" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\intrinsic.natvis" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\liballoc.natvis" "/NATVIS:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\etc\libcore.natvis" "/LIBPATH:C:\Users\Pierre\rust\testmqtt\target\debug\deps" "/LIBPATH:C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib" "C:\Users\Pierre\rust\testmqtt\target\debug\deps\libmosquitto_client-23967bfdaa3a5433.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libstd-8864852919b3dde3.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libpanic_unwind-60bab00b06422126.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libbacktrace-e90b3ab99b608a07.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_demangle-d9b7b1604d471c6c.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libhashbrown-a439eac7fda93b7a.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_alloc-058c975bf38e4686.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libunwind-711d56157cf28645.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcfg_if-d802c196c150a787.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liblibc-7147008fc56d32b8.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\liballoc-57b2ee5c835455f8.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\librustc_std_workspace_core-6391a360e3eeafba.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcore-6c8df881cdc2afb2.rlib" "C:\Users\Pierre\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib\libcompiler_builtins-f998976453a15b70.rlib" "mosquitto.lib" "c.lib" "advapi32.lib" "ws2_32.lib" "userenv.lib" "msvcrt.lib"
  = note: Non-UTF-8 output: LINK : fatal error LNK1181: impossible d'ouvrir le fichier en entrxe9e 'mosquitto.lib'rn     

error: aborting due to previous error

error: Could not compile `testmqtt`.

Caused by:
  process didn't exit successfully: `rustc --edition=2018 --crate-name testmqtt srcmain.rs --color always --crate-type bin --emit=dep-info,link -C debuginfo=2 -C metadata=e2a79a549b8dacef -C extra-filename=-e2a79a549b8dacef --out-dir C:UsersPierrerusttestmqtttargetdebugdeps -C incremental=C:UsersPierrerusttestmqtttargetdebugincremental -L dependency=C:UsersPierrerusttestmqtttargetdebugdeps --extern mosquitto_client=C:UsersPierrerusttestmqtttargetdebugdepslibmosquitto_client-23967bfdaa3a5433.rlib` (exit code: 1)

It is possible to do that, isn’t ?

Regards,

Pierre

Понравилась статья? Поделить с друзьями:

Читайте также:

  • Fatal error при загрузке компьютера
  • Fatal error обои
  • Fatal error неисправимая ошибка пожалуйста перезапустите игру gta 5
  • Fatal error наруто то боруто ниндзя страйкер
  • Fatal error на сайте

  • 0 0 голоса
    Рейтинг статьи
    Подписаться
    Уведомить о
    guest

    0 комментариев
    Старые
    Новые Популярные
    Межтекстовые Отзывы
    Посмотреть все комментарии