LINUX.ORG.RU

Интесресное свойство BASH. Модель Rust + Bash.

 ,


0

3

Интересное свойство bash/shell открыл для себя. Решил попытаться вникнуть в язык Rust. Для примера взял старый, измученный мной, алгоритм перебора перестановок Нараяны. Переписал его и уткнулся в то, что не так легко и элегантно новичку найти способ перевести аргумент командной строки в число. В C89 с приведением типов как-то просто. Искал варианты: все те, что нашёл, относительно синтаксиса и на мой субъективный взгляд, показались трудными для восприятия. Вдруг осенило меня, - можно же использовать в качестве инициализирующего скрипта bash. И появилась такая модель:

  1. Перебор перестановок на Rust с самым простым синтаксисом: данные пользователя хранятся в векторах, в самом скрипте.
  2. Стартовый скрипт на Bash создаёт копию основной программы, забирает аргументы командной строки, создаёт новые векторы и перезаписывает их в основной программе с помощью sed. Безопасно и просто. Результат: https://github.com/dcc0/permutations_rust

Ответ на: комментарий от Manhunt

С какой точки продолжится выполнение спаниковавшего потока?

С момента перехвата.

И panic от этого становится recoverable?

Ок, вероятно, я неправильно выразился. Сказать хотел, что паника принципиально не особо отключается от исключения в плане возможности перехватить/обработать.

То есть, не использовать панику как исключение - это отчасти соглашение, отчасти следствие отсутствия удобного способа сделать catch(T).

Кстати, если паника/исключение - unrecoverable, то «код возврата» - recoverable?.. А почему?

DarkEld3r ★★★★★
()
Ответ на: комментарий от Manhunt

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

andalevor ★★★
()
Ответ на: комментарий от DarkEld3r

Кстати, если паника/исключение - unrecoverable, то «код возврата» - recoverable?.. А почему?

Если говорить о нормальных исключениях, то они recoverable.

Почему в rust было решено, что паника будет unrecoverable - это не ко мне вопрос. Но так написано в документации: https://doc.rust-lang.org/book/ch09-03-to-panic-or-not-to-panic.html

С какой точки продолжится выполнение спаниковавшего потока?

С момента перехвата.

А этот момент перехвата можно произвольным образом размещать в программе (аналогично catch-блокам в c++/python/java)? Если нельзя, то вот и получается, что никакого вменяемого recover после паники уже не сделать.

Manhunt ★★★★★
()
Ответ на: комментарий от Manhunt

Тебе же привели ссылку на std::panic::catch_unwind. В методичке этого не напишут, да.

Siborgium ★★★★★
()
Ответ на: комментарий от anonymous

Переделанный вариант:

let i = loop {
 let mut s = "".to_string();
 std::io::stdin().read_line(&mut s);
 let x : Result<i32, _> = s.parse();
 if let Ok(i) = x {break i}
};
anonymous
()
Ответ на: комментарий от DarkEld3r

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

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

AnonymUser
() автор топика
Ответ на: комментарий от Manhunt

Проблема some_string.parse() состоит в том, что чтобы добраться до собственно int-а и дальше с ним работать по существу, придётся поднасрать в код упоминаниями того, что вместо int-а могла вернуться ошибка. Растоманы, после нескольких лет мучений (с unwrap и с try!), сократили это упоминание до единственной кракозябрины - «?».

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

anonymous
()
Ответ на: комментарий от Manhunt

А этот момент перехвата можно произвольным образом размещать в программе (аналогично catch-блокам в c++/python/java)?

Да.

Если говорить о нормальных исключениях, то они recoverable.

Ну значит и паника тоже.

Другое дело, что язык подталкивает (ну и документация предлагает) использовать панику для «unrecoverable» ошибок.

DarkEld3r ★★★★★
()
Ответ на: комментарий от AnonymUser

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

В сообщении, на которое я отвечал, слово «вопрос» всё-таки содержится. (:

В любом случае, какой смысл писать на форум, если не хочется видеть ответной реакции?

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

Удачи в изучении языков таким образом.

DarkEld3r ★★★★★
()
Ответ на: комментарий от DarkEld3r

Удачи в изучении языков таким образом.

Пример, кстати, возможно, был из какого-то учебника.

anonymous
()
Ответ на: комментарий от anonymous

В rustbook сразу после hello world идёт guessing game, где есть пример получения ввода от пользователя и преобразования его в число. ТС то ли умелый тролль, то ли большой оригинал.

andalevor ★★★
()
Ответ на: комментарий от andalevor

Rustbook не читал, но посмотрю. Спасибо. Про оригинала и тролля: не склонен прямо-таки однозначно детерминировать личность в целом, так сказать, в стиле бинарной оппозиции. :)

Бывает и так, что в человеке всего по чуть-чуть.

P.S. Не ожидал и сам такой джекпот.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 2)
Ответ на: комментарий от anonymous

"".to_string()

даже не знаю какому дебилу посоветовать забаниться

anonymous
()
Ответ на: комментарий от Manhunt

это называется happy path: основная логика идёт в основном «потоке» выполнения, грубо говоря выровнена по левому краю кода, а обработка ошибок выносится в ветки. идиоматический код на го выглядит именно так, тоже самое работает и в с++ и в любом другом языке. погугли, про это есть и посты и видосы.

anonymous
()
Ответ на: комментарий от anonymous

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

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

anonymous
()

Конвертация на чистом С

Все же: на С довольно красиво можно конвертировать аргумент в число без atoi и прочего. Голым так, сказать, stdio:

[code=c]

#include <stdio.h>

int main (int argc, char * argv[]) {

int i = 0;
int j = 1;
int sum = 0;
int vector[30] = {};

/*Читаем символы аргумента в вектор*/	
for (i = 0;  argv[1][i] != '\0'; i++)
vector[i] = argv[1][i]-48;

i = i - 1;
/*Помножим числа в знаках на кратные 10*/
for (i; i > -1; i--, j = j*10) 
vector[i] = vector[i]*j;


/*Плюсуем значения векторов в одно целое*/
for (i = 0; argv[1][i] != '\0'; i++) 
sum+=vector[i];
	
printf("%d", sum);

}

[/code]

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 3)
Ответ на: комментарий от anonymous

это называется happy path: основная логика идёт в основном «потоке» выполнения, грубо говоря выровнена по левому краю кода, а обработка ошибок выносится в ветки.

Как быть с тем, что у happy path также могут быть ветки, или, например, требующие отступов циклы?

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 1)
Ответ на: комментарий от Manhunt

Это был первый попавшийся пример ошибки

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

DonkeyHot ★★★★★
()
Ответ на: комментарий от DonkeyHot

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

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

Моё утверждение состояло в том, что модуль парсинга не должен содержать упоминаний об ошибках ввода-вывода (которые могут приехать из модуля ввода-вывода). То есть парсеру достаточно учитывать, что запрос за новым блоком данных может быть неуспешным, но вот разновидности неуспеха ему должны быть глубоко безразличны. При нормальной инверсии зависимостей, парсер и знать не будет, что поставщиком данных является модуль вводы-вывода.

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

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 2)

Ещё интересностей

Всё тоже самое на С89 stdio. С преобразованием в целое кустарным способом.

https://github.com/dcc0/my_functions_C89/tree/main/permutations Никакого bash с кучей проверок.

Почти один в один условия (у С только приходится ещё цикл делать, чтобы напечатать вектор целых).

И получается все же, даже видимым образом С быстрее.

(Но надо сказать чистый код Rust доставляет эстетическое наслаждение, loop - лаконично). Если не добавлять всякие конструкции в начало, то отлично.

AnonymUser
() автор топика
Последнее исправление: AnonymUser (всего исправлений: 1)
Ответ на: комментарий от Manhunt

Моё утверждение состояло в том, что модуль парсинга не должен содержать упоминаний об ошибках ввода-вывода

А моё в том, что в модуле парсинга не должно быть упоминаний ввода-вывода. Вроде и не спорим.

Где тз расходятся, так это в оценке

сократили это упоминание до единственной кракозябрины - «?»

Как по мне, это довольно малошумный способ выбрать вариант обработки «детали там-то».

DonkeyHot ★★★★★
()
Ответ на: комментарий от Manhunt

Код-то может быть и не смешан, но парсер может запрашивать очередной блок входных данных, что повлечет ввод-вывод (естественно, с потенциальными ошибками ввода-вывда).

Но парсеру эти ошибки никто не передаст. Они будут обработаны там где происходит IO.

trait IO {
    fn read_more(&mut self, buffer: &mut [u8]) -> usize;
}

fn reader() -> impl IO { /* handle io errors here */ }

fn parse(io: &mut impl IO) -> Data { /* ... */ }

fn main() {
    let mut io = reader();
    let data = parse(&mut io);
    // ...
}

И никаких ?.

vlad9486
()
Последнее исправление: vlad9486 (всего исправлений: 1)
Ответ на: комментарий от vlad9486

Речь о том, что функция read_more() при очередном её вызове может вместо очередного блока данных вернуть ошибку.

Manhunt ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.