Комментарии 74
Таки-меня коробит, что для такой важной и распространенной вещи как обработка ошибок по всему коду используется макрос, который еще и меняет поток выполнения. Не то что бы я видел в этом какой-то вот прямо практический вред, нооо как-то криво это. Ожидаю рано или поздно какого-то обобщенного решения интегрированного в сам язык, вроде же были какие-то rfc.
+5
RFC есть (https://github.com/rust-lang/rfcs/pull/243), но оно не движется.
Автор не хотел вставлять неявный вызов `Into::into` в `?`, человек из core team с ним не согласился, так всё пока и заглохло, потому что особо и не горит. Но рано или поздно будет, можно их попинать в комментах для ускорения.
Автор не хотел вставлять неявный вызов `Into::into` в `?`, человек из core team с ним не согласился, так всё пока и заглохло, потому что особо и не горит. Но рано или поздно будет, можно их попинать в комментах для ускорения.
+2
Коробит, потому что непривычно? Макросы в Rust реализованы достаточно неплохо для того, чтобы быть хорошим инструментом для решения более-менее повседневных задач, не вызывая при этом боли, которая может возникнуть например в C++. Тем более, обработка ошибок через
Когда я только начинал писать на Rust, меня тоже поначалу удивило отсутствие специального инструментария для обработки ошибок. Но набравшись некоторого опыта, я совершенно точно могу сказать, что не жду никакого «нормального решения» для обработки ошибок, и скорее всего буду против такого новшества. И это вопрос не привычки, а реального удобства.
try!
получается гораздо короче, чем использование try-catch блока в тех же сценариях. Когда я только начинал писать на Rust, меня тоже поначалу удивило отсутствие специального инструментария для обработки ошибок. Но набравшись некоторого опыта, я совершенно точно могу сказать, что не жду никакого «нормального решения» для обработки ошибок, и скорее всего буду против такого новшества. И это вопрос не привычки, а реального удобства.
+1
Тем не менее, макросы, меняющие поток управления — это действительно неожиданно и поэтому может быть плохо.
try! спасает только то, что он всего один, достаточно прост и быстро узнается в процессе изучения языка.
try! спасает только то, что он всего один, достаточно прост и быстро узнается в процессе изучения языка.
+1
Я думаю, именно потому, что вызовы макроса могут вести себя не так тривиально, как вызовы функции, они обязательно требуют специального обозначения вроде
К счастью, макросы, которые регулярно используются в коде можно пересчитать на пальцах:
Наверное можно было бы расширить синтаксис языка специльно для исключений, но такое расширение все-равно будет следовать логике макроса
foo!
. Это что-то вроде «будь внимателен, здесь происходит что-то необычное».К счастью, макросы, которые регулярно используются в коде можно пересчитать на пальцах:
try!, println!, format!, vec!, assert! и assert_eq!
Наверное можно было бы расширить синтаксис языка специльно для исключений, но такое расширение все-равно будет следовать логике макроса
try
. Например, что-то вроде foo(try bar())
. Для остальных случаев есть более универсальная конструкция match
, которая уже и так умеет все то, что в обычных языках умеет try-catch блок. Единственное отличие – match работает для каждого конкретного вызова, в то время как try-catch может оборачивать целый блок кода. Но я бы поспорил о том, что это недостаток для языка программирования, который делает ставку на надежность.+3
Ну как, я относительно давно на ржавчине пытаюсь писать, так что дело не просто в непривычности.
С одной стороны, я считаю что хороший макрос являет собой цельную абстракцию, действие которой не выходит за скобки вызова, вроде как и в официальных доках чего-то такое было. А тут она берет и влияет на код вокруг.
С другой, к макросам я отношусь как к средству, к которому прибегают когда у самого языка не хватает выразительности, а тут у нас оочень частая операция. Тоже странно.
Повторюсь, каких-то жутких практических недостатков в данном конкретном случае я не вижу — согласен с Михаилом, что ситуацию спасает одиночество `try!`. Но мне было бы комфортнее, если бы вышеуказанный RFC довели до ума и реализовали, пускай оно даже один в один как `try!` работало бы. Или даже что бы таки реализовали HKT и ввели в язык do-нотацию :).
С одной стороны, я считаю что хороший макрос являет собой цельную абстракцию, действие которой не выходит за скобки вызова, вроде как и в официальных доках чего-то такое было. А тут она берет и влияет на код вокруг.
С другой, к макросам я отношусь как к средству, к которому прибегают когда у самого языка не хватает выразительности, а тут у нас оочень частая операция. Тоже странно.
Повторюсь, каких-то жутких практических недостатков в данном конкретном случае я не вижу — согласен с Михаилом, что ситуацию спасает одиночество `try!`. Но мне было бы комфортнее, если бы вышеуказанный RFC довели до ума и реализовали, пускай оно даже один в один как `try!` работало бы. Или даже что бы таки реализовали HKT и ввели в язык do-нотацию :).
+1
А как код выглядел бы с do-нотацией? Не получится ли слишком громоздко?
0
Полагаю как-то так: ideone.com/DlGYHp со строки 32.
Всё, что выше — просто чтоб компилировалось.
Всё, что выше — просто чтоб компилировалось.
0
> А как код выглядел бы с do-нотацией?
Сейчас есть накостыленый на макросах mdo! — https://github.com/TeXitoi/rust-mdo — лучше без HTK особо не сделаешь. С ним как-то так выходит:
Если интегрировать в язык, то, наверное, можно и немного покороче/покрасивей синтаксис придумать.
> Не получится ли слишком громоздко?
Может, от конкретного кода зависит. Функции, возвращающие чего-то левое (как println! в примере), которые не выходит вынести за рамки do, конечно, придется «втягивать».
Если что, я на знатока функциональных буррито не претендую, но идея кажется заслуживающей проработки)
Сейчас есть накостыленый на макросах mdo! — https://github.com/TeXitoi/rust-mdo — лучше без HTK особо не сделаешь. С ним как-то так выходит:
fn write_to_file_using_try() -> io::Result<()> {
let mut file = try!(File::create("my_best_friends.txt"));
try!(file.write_all(b"This is a list of my best friends."));
println!("I wrote to the file");
Ok(())
}
fn write_to_file_using_mdo() -> io::Result<()> {
mdo! {
mut file =<< File::create("my_best_friends.txt");
ign file.write_all(b"This is a list of my best friends.");
ign Ok(println!("I wrote to the file"));
ret Ok(())
}
}
Если интегрировать в язык, то, наверное, можно и немного покороче/покрасивей синтаксис придумать.
> Не получится ли слишком громоздко?
Может, от конкретного кода зависит. Функции, возвращающие чего-то левое (как println! в примере), которые не выходит вынести за рамки do, конечно, придется «втягивать».
Если что, я на знатока функциональных буррито не претендую, но идея кажется заслуживающей проработки)
0
Я Все хотел задать вопрос, Вот Rust И GO, высоконагруженные платформы, А есть ли succes story от их использования,
Я например хочу написать веб приложение, что лучше использовать ??(Best practices)? у Го и Rust есть предпосылки для роста, это не NodeJs со своей лапшей (Callbacki)
Я например хочу написать веб приложение, что лучше использовать ??(Best practices)? у Го и Rust есть предпосылки для роста, это не NodeJs со своей лапшей (Callbacki)
0
New York Times вроде как переписали кучу всего на Go
https://www.youtube.com/watch?v=bAQ9ShmXYLY
https://www.youtube.com/watch?v=bAQ9ShmXYLY
0
Можно здесь подсмотреть github.com/golang/go/wiki/GoUsers
То есть, Go используется дофига где. Насчёт применения Rust в продакшене пока рано говорить.
То есть, Go используется дофига где. Насчёт применения Rust в продакшене пока рано говорить.
-4
Кроме OpenDNS чего не слышал. И то обвязочка для сишной либы, вы серьёзно называете это продакшеном?
-5
Логика на уровне «я не слышал, значит этого нет». А я слышал про Skylight и MaidSafe, и чего, кто теперь прав?
Да, это боевой код, который работает в реальных условиях — это production. Его размер здесь не важен, но если хотите, то вот цифры (это честные SLOC, без пробелов и комментариев):
У MaidSafe всё ядро распределённой сети на Rust (14000 строк).
Redox — это активно разрабатываемая ОС на Rust. 40000 строк кода на Rust. И пока вы не возразили, что этим «никто не пользуется» или «вы про это не слышали» — вспомните, как начинался Linux.
Да, это боевой код, который работает в реальных условиях — это production. Его размер здесь не важен, но если хотите, то вот цифры (это честные SLOC, без пробелов и комментариев):
У MaidSafe всё ядро распределённой сети на Rust (14000 строк).
Redox — это активно разрабатываемая ОС на Rust. 40000 строк кода на Rust. И пока вы не возразили, что этим «никто не пользуется» или «вы про это не слышали» — вспомните, как начинался Linux.
+3
Логика на уровне, что в списке про Go присутствует индустрия. А ваш список — карта песочниц в округе.
Вы поймите, продакшен это коммерчески успешные проекты, когда люди за свои ошибки отвечают жопами, а код прибывает по 10к в неделю минимум. Когда можно набрать 5 человек с улицы и вовлечь в проект меньше, чем за полгода. Ваш список это хороший индикатор, но вы оффтопите в этом треде про продкшен.
Его размер здесь не важен, но если хотите, то вот цифры (это честные SLOC, без пробелов и комментариев)Вообще говоря важен, особенно не в абсолютных цифрах, а в степени вовлечённости в архитектуре. MaidSafe ещё не релизнулся, вы не компетентны если называете opens-source поделку до первого RC «продакшеном». 14000 LOC это смешно, у меня хобби-проект на Go за полтора месяца вышел на 8000. 14000 с учётом специфики задач это уровень концепта.
Redox — это активно разрабатываемая ОСЯ не буду вас ловить и проверять, насколько активно и какие там люди (больше, чем полтора ботана, надеюсь). По моему опыту разработки модулей и драйверов Linux — раст там вообще ничем не поможет. А до продакшена этой поделке лет 5 в лучшем случае, 20 в обычном.
Вы поймите, продакшен это коммерчески успешные проекты, когда люди за свои ошибки отвечают жопами, а код прибывает по 10к в неделю минимум. Когда можно набрать 5 человек с улицы и вовлечь в проект меньше, чем за полгода. Ваш список это хороший индикатор, но вы оффтопите в этом треде про продкшен.
-8
На Skylight-то посмотрите, прежде чем обвинять в некомпетентности.
+5
больше, чем полтора ботана, надеюсьЛинус вон вообще один начинал, в чём проблема-то?
Да и, что меня ловить-то, я и сам поймаюсь.
Redox SLOCs
А code churn на уровне 200 000 — 2 000 000 строк это уже извините меня не «поделка», как ни крути.
А до продакшена этой поделке лет 5 в лучшем случае, 20 в обычном.Сколько лет пройдёт до того, как махровая индустрия возьмёт на вооружение Rust обсуждать есть смысл только с учётом того, что Go появился на 3 года раньше Rust. Прямые сравнения неуместны.
+4
продакшен это коммерчески успешные проекты, когда люди за свои ошибки отвечают жопами, а код прибывает по 10к в неделю минимум.
Можно узнать источник этого определения?
+6
То есть, к определению
боевой код, который работает в реальных условиях — это productionтоварища mkpankov у вас вопросов нет? Или вы согласны, что он неадекват и интересуетесь именно этим определением? Что-ж почитайте вот jdevelop.blogspot.ru/2013/03/blog-post.html
-6
Я например хочу написать веб приложение, что лучше использоватьRuby on Rails, потому что быстрее и проще, а узкие места переписать на Go всегда успеете. Всё равно их переписывать придётся.
0
Best practices для Rust пока нет.
История успеха — это Servo. Он рисует страницы в 2 раза быстрее Gecko в одном потоке и ещё быстрее в многопоточном режиме.
А из коммерческих пользователей есть как минимум Maidsafe, Skylight, OpenDNS. У них в разных местах есть посты о том, почему они выбрали Раст.
История успеха — это Servo. Он рисует страницы в 2 раза быстрее Gecko в одном потоке и ещё быстрее в многопоточном режиме.
А из коммерческих пользователей есть как минимум Maidsafe, Skylight, OpenDNS. У них в разных местах есть посты о том, почему они выбрали Раст.
+7
История успеха — это Servo.
Заинтересовал, погуглил. Наткнулся многократно на то, что его пока не собираются использовать в Firefox. Задумался ещё больше. Ведь разработка такой большой вещи занятие весьма эпохальное (это работа не для 5 программистов). С какой целью тогда они его делают?
0
Не совсем так.
Вот план реализации Servo: github.com/servo/servo/wiki/Roadmap. Моё понимание таково: Servo пока просто не готов к боевому применению. Хотя некоторые сайты уже отрисовываются так же хорошо, как и в Gecko.
Насколько я помню, в целом Mozilla действует так: постепенно заменяют компоненты в Firefox на те, что используется в Servo, так что в конце они будут использовать одно и то же, а затем можно и движок заменить.
Вот план реализации Servo: github.com/servo/servo/wiki/Roadmap. Моё понимание таково: Servo пока просто не готов к боевому применению. Хотя некоторые сайты уже отрисовываются так же хорошо, как и в Gecko.
Насколько я помню, в целом Mozilla действует так: постепенно заменяют компоненты в Firefox на те, что используется в Servo, так что в конце они будут использовать одно и то же, а затем можно и движок заменить.
+4
В нём уже все спецификации реализовали или только те, что можно быстро нарисовать? :-)
0
это не NodeJs со своей лапшей (Callbacki)
Лапша у вас на ушах, уважаемый. Вы внимательно погуглите магические 'javascript promise', 'javascript async/await', 'javascript es2015', чтобы глупостей не говорить.
+1
Это конечно все хорошо, просто отладка осложняется, и код не очевиден, Я хотел уже осваивать Node.JS но потом увидел что на код надо смотреть не линейно а сначала код и заглушка(Callback) которая после нее. Конечно я понимаю таково преимущество Асинхронности, может быть проблема старого поколения что на код они смотрят линейно ???
0
javascript es2015
Его V8 уже поддерживает стабильно?
0
Rust, go, erlang, haskell, node, r&r, python, php, scala, groovy, dart, java, kill, kill, kill me…
-12
К сожалению очень сложно представить выгоду от всех этих сложностей языка в реальных проектах. Там где нужен жесткий real time или крайне стабильный драйвера Rust наверно и крут. Но вот касательно всех других проектов — думаю для массового рынка он будет слишком невыгоден скоростью разработки.
0
Почему-то все очень любят оценивать только скорость разработки, забывая про скорость отладки. И проблема в том, что эти две величины связаны между собой не так просто, как хотелось бы: почти любой многопоточный алгоритм значительно сложнее отлаживать, чем идентичный ему однопоточный, при этом оба могут быть записаны в одну строку (а-ля records.map(processFn) и records.parallelMap(processFn)). В языках без GC к этому добавляются проблемы использования объектов после разрушения и т.п.
Баги в программе — это ещё и удар по репутации. Уж лучше потратить в два раза больше времени на написание кода, чем написать код в два раза быстрее, а потом столько же его отлаживать (ну, это как повезёт), вдобавок теряя клиентов и получая негативные отзывы.
Баги в программе — это ещё и удар по репутации. Уж лучше потратить в два раза больше времени на написание кода, чем написать код в два раза быстрее, а потом столько же его отлаживать (ну, это как повезёт), вдобавок теряя клиентов и получая негативные отзывы.
+4
Вам никто ведь не мешает делать unwrap везде, а затем постепенно рефакторить. Стабильность теряется разумеется.
+3
Распространенность в стандартной библиотеке возвратов структуры Result вместе с рекомендованным способом его обработки через макрос try! (который по сути пробрасывает ошибку вверх по стеку вызовов) весьма напоминает эмуляцию throw exception из Java и подобных языков.
0
Нечто вроде эмуляции. Эксепшены более тяжеловесны, так как в них (как минимум) сохраняется весь stack trace. (Про другие причины их тяжеловесности в разных языках я когда-то читал, но уже многое подзабыл, и ссылку на статью найти не могу).
Похожая эмуляция исключений, кстати, недавно появилась в swift 2.0, и меня это очень сильно порадовало. Все же не очень удобно и читабельно плодить кучу if-ов для проверки ошибок после вызова каждой функции. Но решение в Rust мне видится более гибким, так как можно делать всякие функциональные чудеса с помощью map, map_err и проч., полностью отказавшись от try! при необходимости.
Похожая эмуляция исключений, кстати, недавно появилась в swift 2.0, и меня это очень сильно порадовало. Все же не очень удобно и читабельно плодить кучу if-ов для проверки ошибок после вызова каждой функции. Но решение в Rust мне видится более гибким, так как можно делать всякие функциональные чудеса с помощью map, map_err и проч., полностью отказавшись от try! при необходимости.
0
Можно автору статьи несколько вопросов?
Какой размер имеет в Rust экземпляр типа i32? В Си i32 – элементарный тип. Скорее всего в Rust i32 тоже элементарный, т.е. не класс. Поэтому его размер, скорее всего, 4 байта. И какой размер имеют экземпляры типов Option и Result<i32, E>? И ещё вопрос – указатель в Rust является элементарным типом или нет? И каков его размер?
Как обработать в Rust возникающие при сложении переполнения, т.е. ошибки?
Какой размер имеет в Rust экземпляр типа i32? В Си i32 – элементарный тип. Скорее всего в Rust i32 тоже элементарный, т.е. не класс. Поэтому его размер, скорее всего, 4 байта. И какой размер имеют экземпляры типов Option и Result<i32, E>? И ещё вопрос – указатель в Rust является элементарным типом или нет? И каков его размер?
Как обработать в Rust возникающие при сложении переполнения, т.е. ошибки?
+1
Автор статьи вам скорее всего не ответит, поскольку не читает Хабр. Отвечу я как переводчик.
i32 – элеменентарный тип, его размер 4 байта. В Rust вообще нет понятия класса.
Размер Option<T> равен размеру T + дискриминант (обычно 1 байт) + выравнивание.
Размер Option<&T> равен размеру указателя для вашей архитектуры. Дискриминант не нужен, поскольку значение None кодируется как нулевой указатель. В Rust нет нулевых указателей, так что сам &T никогда не будет равен null.
Размер Result<T, E> равен размеру дискриминанта (1 байт) + размеру наибольшего возможного значения (или размер T, или размер E) + выравнивание.
Арифметические операции по умолчанию игнорируют переполнение, но если вам нужно их обрабатывать, можно воспользоваться методами checked_add, checked_mul и т.д. В случае с i32 они возвращают результат Option<i32>.
i32 – элеменентарный тип, его размер 4 байта. В Rust вообще нет понятия класса.
Размер Option<T> равен размеру T + дискриминант (обычно 1 байт) + выравнивание.
Размер Option<&T> равен размеру указателя для вашей архитектуры. Дискриминант не нужен, поскольку значение None кодируется как нулевой указатель. В Rust нет нулевых указателей, так что сам &T никогда не будет равен null.
Размер Result<T, E> равен размеру дискриминанта (1 байт) + размеру наибольшего возможного значения (или размер T, или размер E) + выравнивание.
Арифметические операции по умолчанию игнорируют переполнение, но если вам нужно их обрабатывать, можно воспользоваться методами checked_add, checked_mul и т.д. В случае с i32 они возвращают результат Option<i32>.
+4
Простите, я вас обманул по-поводу переполнения:
Обычное сложение
Метод
Метод
Метод
Обычное сложение
150u8 + 150u8
паникует в случае переполнения (и корректно завершает поток).Метод
150u8.checked_add(150u8)
возвращает Option<T> со значением None.Метод
150u8.saturating_add(150u8)
возвращает граничное значение (255).Метод
150u8.wrapping_add(150u8)
игнорирует переполнение (44).0
На данный момент, если не ошибаюсь, паникует только в отладочной сборке. Это может быть важно)
+3
Да, точно, для release оператор
+
ведет себя аналогично wrapping_add
.+1
Если Option имеет дискриминант (или дескриптор, т.е. описание? В языке Алгол-68 применялся термин «паспорт», этот паспорт дополнительно описывал объекты), то из функции нельзя вернуть Option в 32-разрядном регистре. Некоторая потеря эффективности в пользу надёжности.
Установил Rust себе на Windows XP – не работает. Потом узнал, что эта платформа не поддерживается. Тогда поставил на 32-разрядную Windows 7. Компилятор сообщает о синтаксической ошибке на «hello world», взятый из учебника. Наверно, нужен Linux… Компилятор Rust выдаёт не исполняемый код, а код в LLVM IR. А под Windows единственный инструмент, который превращает код LLVM IR в исполняемый – Visual C++. Как-то не по фэншую – сочетание свободного ПО и проприетарного… Или я неправильно информирован?
Установил Rust себе на Windows XP – не работает. Потом узнал, что эта платформа не поддерживается. Тогда поставил на 32-разрядную Windows 7. Компилятор сообщает о синтаксической ошибке на «hello world», взятый из учебника. Наверно, нужен Linux… Компилятор Rust выдаёт не исполняемый код, а код в LLVM IR. А под Windows единственный инструмент, который превращает код LLVM IR в исполняемый – Visual C++. Как-то не по фэншую – сочетание свободного ПО и проприетарного… Или я неправильно информирован?
0
> Установил Rust себе на Windows X
Но сегодня 2015 год же!
> А под Windows единственный инструмент, который превращает код LLVM IR в исполняемый – Visual C++. Как-то не по фэншую – сочетание свободного ПО и проприетарного… Или я неправильно информирован?
Если бы вы реально хотели посмотреть, то увидели, что у раста два варианта под windows. Через MSVC и Mini-GW.
> Компилятор сообщает о синтаксической ошибке на «hello world», взятый из учебника.
Может програмирование это не для вас?
Но сегодня 2015 год же!
> А под Windows единственный инструмент, который превращает код LLVM IR в исполняемый – Visual C++. Как-то не по фэншую – сочетание свободного ПО и проприетарного… Или я неправильно информирован?
Если бы вы реально хотели посмотреть, то увидели, что у раста два варианта под windows. Через MSVC и Mini-GW.
> Компилятор сообщает о синтаксической ошибке на «hello world», взятый из учебника.
Может програмирование это не для вас?
-1
Ни к чему нападать на человека, который заинтересовался языком, задаёт нормальные вопросы и пытается разобраться.
+1
Некоторая потеря эффективностиЯ не могу понять, в чем потеря эффективности? Не сущесвует никакой возможности впихнуть тип «i32 или ничего» в 4 байта. По-любому нужен еще хотя-бы один бит, чтобы кодировать это «ничего». Как раз для этого необходим дискриминант. Никто вам не мешает возвращать из функции просто i32, размером в 4 байта.
+1
На правах безумной идеи: тегированная память, как в Эльбрусах, была бы весьма кстати.
0
Я не могу понять, в чем потеря эффективности? Не сущесвует никакой возможности впихнуть тип «i32 или ничего» в 4 байта.
В Си эта проблема решалась значениями-исключениями
hFile = CreateFile(...);
if (hFile == INVALID_NAHDLE_VALUE) ...
Никто вам не мешает возвращать из функции просто i32, размером в 4 байта.
и потерять всю эту безопасность, паттерн-матчинг и вернуться на ступень назад
0
> В Си эта проблема решалась значениями-исключениями
И это печально.
И это печально.
+4
Не понимаю зацикленной логики. Да, в Си это часто решалось значениями-исключениями. Да, это было быстрее. Но это менее безопасно. Сделали более безопасно. Нам не нравится что это стало медленнее. Так что же мы изначально хотели, быстро или безопасно?
+1
Мы хотели бескомпромиссно, в этом идеология си/си++
Если для этого нужно усложнять концепцию, вставив в описание Option ручное указание значения-исключения для NONE, такое усложение стоит выигрыша в скорости.
Если для этого нужно усложнять концепцию, вставив в описание Option ручное указание значения-исключения для NONE, такое усложение стоит выигрыша в скорости.
-1
Это не «бескомпромиссно», это небезопасно.
Позвольте вопрос: вы на Си пишете или так, сопереживаете?
Если для этого нужно усложнять концепцию, вставив в описание Option ручное указание значения-исключения для NONE, такое усложение стоит выигрыша в скорости.Да, а вы как себе представляете решение этой проблемы без этого, но чтобы нельзя было забыть обработать ошибку?
Позвольте вопрос: вы на Си пишете или так, сопереживаете?
+2
Да, а вы как себе представляете решение этой проблемы без этого, но чтобы нельзя было забыть обработать ошибку?
Наверное плохо объяснил. Всё остаётся по-прежнему, и возвращается Option, но компилятору даётся хинт, что значение INVALID_HANDLE_VALUE трактуется как None, таким образом результат помещается в int32
0
Такой хинт уже реализован в Rust для типа
Option<&T>
. Такой тип занимает 4 байта (для 32-битной архитектуры), и значение 0 трактуется как None.+1
Да, это интересная идея. Я думаю, что сейчас это требует поддержки в LLVM, поэтому сложно делать это для любых типов.
0
Разве тут что-то требуется от LLVM? Сейчас для реализации хака с Option<&T> достаточно обернуть данные в обертку NonZero. Можно себе представить, что нечто подобное можно сделать для произвользного диапазона значений. Но это все начинает напоминать оптимизации в стиле «давайте хранить 3 разных значения в двух байтах». Можно, но стоит ли?
0
Я попробовал посмотреть на разницу в LLVM IR для ссылки и указателя: is.gd/EyTrrF
Как видим, ссылка явно dereferenceable. Я думаю, что для LLVM указатели с возможностью обнуления — особый случай, и они специально поддержаны. Обобщённого же механизма нет. Да и в core только NonZero, а общего типа с возможностью указать, какие значения особые, нет.
Как видим, ссылка явно dereferenceable. Я думаю, что для LLVM указатели с возможностью обнуления — особый случай, и они специально поддержаны. Обобщённого же механизма нет. Да и в core только NonZero, а общего типа с возможностью указать, какие значения особые, нет.
0
А давайте поговорим о том, как приведенный вами пример позволяет узнать причину ошибки?
0
В качестве примера, в glibc есть костыль с глобальной errno. Про многопоточность естественно тут приходится забыть.
Сам я за подход rust. Обычно накладные расходы не столь критичны. А если уж очень надо — можно как в C сделать, кто мешает то…
Сам я за подход rust. Обычно накладные расходы не столь критичны. А если уж очень надо — можно как в C сделать, кто мешает то…
0
Про многопоточность естественно тут приходится забыть.
errno давно уже объявляется как __thread (для MSVC __declspec(thread))
у каждого потока своя переменная errno.
0
как приведенный вами пример позволяет узнать причину ошибки?
пример скорее был для Option, а не Result, а с Result можно сделать хинты, мапящие разные ошибки на константы, которые не может вернуть ф-ция (например, если возвращается pointer таких недопустимых результатов очень много)
0
Компилятор сообщает о синтаксической ошибке на «hello world», взятый из учебника.Какая ошибка у вас?
Компилятор Rust выдаёт не исполняемый код, а код в LLVM IR.Это не так, компилятор Rust как исполняемый файл rustc выдаёт исполняемый код. LLVM IR используется внутри и скрыто от пользователя. Visual C++ используется не здесь, а при компоновке с системными библиотеками и нужен если вам нужно MSVC ABI — из всего Visual C++ нужен лишь link.exe.
0
Вместо макроса try! можно использовать оператор ? для автоматического возврата ошибок
use std::fs::File;
use std::io::{self, Read};
use std::path::Path;
#[derive(Debug)]
enum CliError {
IoError(io::Error),
ParseError(std::num::ParseIntError),
}
impl From<io::Error> for CliError {
fn from(err: io::Error) -> CliError {
CliError::IoError(err)
}
}
impl From<std::num::ParseIntError> for CliError {
fn from(err: std::num::ParseIntError) -> CliError {
CliError::ParseError(err)
}
}
//fn file_double<P: AsRef<Path>>(file_path: P) -> Result<i32, CliError>
fn file_double(file_path: AsRef<Path>) -> Result<i32, CliError>{
let mut file = File::open(file_path)?;
let mut contents = String::new();
file.read_to_string(&mut contents)?;
let n: i32 = contents.trim().parse()?;
Ok(2 * n)
}
fn main() {
match file_double("path/to/your/file.txt") {
Ok(result) => println!("Result: {}", result),
Err(e) => eprintln!("Error: {:?}", e),
}
}
Или даже так
fn file_double(file_path: AsRef<Path>) -> Result<i32, CliError>
File::open(file_path)?
.read_to_string(&mut String::new())?
.trim()
.parse::<i32>()
.map(|n| 2 * n)
0
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Обработка ошибок в Rust