for/while?
А зачем?
они и так выражения, только ничего полезного (в отличие от loop) не могут вернуть https://doc.rust-lang.org/reference/expressions/loop-expr.html
удобненько же, вместо let mut val = None; while .. { ... if cond { val = Some(kek); break; } ... } let val = val; писать просто let val = while .. { ... if cond { break kek; } ... };
И прибить циклы гвоздями к Option? Ну такое...
Почему бы и нет? Вроде вполне себе тип для большинства случаев
В принципе, вариант, но слишком opinionated для Rust IMO.
ну да, выходит такой рфц это breaking-change
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=e089da8e17b81b75745f63d888bbcdb9 ну вот зачем так делать :\
почему? нет, вроде, просто потенциальное расширение. только из-за опциональности оно правда выглядит не так хорошо, как давно принятый брейк из loop
на самом деле там просто else должен быть, даже вроде был рфц
все еще не понимаю в чем проблема. так же как с loop будет же - если брейков нет или они без аргументов, то (), иначе используется тип аргумента
Во, точно, такой даже видел да
let val = while .. { ... } else { // executed if no break occurred };
https://github.com/rust-lang/rfcs/blob/master/text/3137-let-else.md вот такой только нашел, для циклов не вижу
else ветка должна выполняться, если цикл ни разу не выполнялся.
https://internals.rust-lang.org/t/pre-rfc-break-with-value-in-for-while-loops/11208 там ссылки есть на другие дискуссии
полноценного рфц, вроде, про это так и не завели же,да?
почему? let mut x = true; let val = while x { x = false; } else { 0 }; не сможет вернуть значение, в твоём случае
https://github.com/rust-lang/rfcs/pull/3163 вот нашел свеженько закрытый
Он просто не типизируется. Тело цикла должно "возвращать" значение того же типа, что и else ветка. Я вообще не понимаю, зачем нужны циклы, которые возвращают единственное значение. Циклы нужны чтобы накапливать значения — т.е. они должны работать с моноидальными типами.
Ерунда, break может быть недостижим, иначе цикл не цикл получается. Обе ветви типизированы одинаково, просто значение не было возвращено до завершения, поэтому дефолтный вариант выбирается.
Цикл и вообще может не завершаться — я не понимаю, чего вы на break завязываетесь. Для Rust-style логично было бы ориентироваться на последнее выражение в теле цикла, так же как для функций.
исполнение тогда совсем не очевидным выходит имхо
Именно поэтому это не очень хорошая идея в принципе. Особенно, в отсутствии явных моноидов. Хотите посмотреть на "крутые" "циклы как выражения" — посмотрите на loop macro в Common Lisp или на Ruby. Я не фанат ни первого, ни второго решения.
да, в рфц выше уже привели кейсы с питона и еще чего-то, там опыт вышел так себе
Ну, Лисперы-то любят свои сверхмощные циклы, а вот Рубисты действительно не пользуюся, да большинство и не знает про такое. 😊
let mut x = true; let val = while x { if false { break 1; } x = false; } else { 0 }; ? Циклы могут, например, искать или акомулировать значение. Тот-же find это for x in xs { if x == v { break Some(x) } } else { None }
В питоне кстати есть else для циклов, который выполняется когда break не было: https://docs.python.org/3/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops
К break привязка идёт потому что break это return для лупов, по сути. И потому что та же привязка есть для loop{} else же нужен, потому что в отличии от loop{} другие циклы могут завершиться до достижения break, вроде всё логично
Смотрите, у нас есть кучка вариантов, не все из которых исключают остальные: 1. бесконечный цикл 2. цикл выполнился 0 раз 3. цикл выполнился N раз 4. в процессе выполнения дошли до break 5. до break выполнение никогда не доходило И нам нужно ответить на 2 вопроса по каждому случаю: а) какая семантика у этого случая, б) как мы этот случай типизируем. В частности, мне непонятно как Вы хотите типизировать случай 5, особенно если никаких break внутри цикла вообще нет?
И вот как в функции можно дойти до конца функции без явного return — так и в цикле, если это не loop. Значит, и типизировать их нужно аналогичным образом.
Десахаринг вроде тоже тривиальный, можно хоть макросом сделать: while cond { if false { break 0; } } else { 1 } <=> loop { if cond { if false { break 0; } } else { break 1; } }
Срабатывание else ветки всегда при нормальном завершении цикла? Несколько контринтуитивная семантика. 🤷♀️
случай 5 типизируется else'ом. while cond {} else { x } всегда "возвращает" x, если цикл не бесконечный
А откуда мы должны знать, бесконечный он или нет? 😉
Нет. Доход до конца функции её завершает, а доход до конца цикла — нет. loop {} и так бесконечный, нем не нужно писать loop { continue }, чтобы он не завершился на первой итерации и не "вернул" ()
А какая нам разница? Мы всегда предполагаем что в данном случае после завершения цикла, возвращается x. Если цикл бесконечный, то мы просто никогда не дойдём до этого
Это принцип работы ops::ControlFlow и вообще всего, связанного с траем.
> Доход до конца функции её завершает, а доход до конца цикла — нет. Вот иногда доход до конца цикла его завершает, а иногда — нет. Поэтому и нужен моноид. 😊 А с loop всё понятно, да.
ОК, я понял какую семантику Вы предлагаете. Она даже непротиворечивая, скорее всего. Но мне кажется контринтуитивной, я бы так не стал делать, и пользоваться тоже не стал. 🤷♀️
👍 Я тоже не уверен, что такое нужно.
1. Ничего не возвращает, типизация else. 2. Вернёт то, что в else. 3+4. Вернёт то, что в break, типизируется либо else, либо break с инфером else, либо указанием типа с инфером обоих. 3+5. Вернёт то, что в else, прочее эквивалентно п.п. Какой есть другой вариант?
Другой вариант, очевидно, типизировать как функции — по последнему выражению. break — полнотью аналогично early return. На случай если цикл — в отличие от функции — выполнился 0 раз — блок else, значение в котором должно иметь тот же тип. Семантически — снова как для функции, возвращаем значение последнего выражения с последней итерации или break, если он выполнился. Либо else, если в цикл вообще не заходили. По-моему, это самый прямолинейный вариант, и такой же ограниченный как предложенный Вами с @wafflelapkin потому что нельзя накапливать значения в моноиде. Только руками это делать, но так можно и в обычном цикле уже сейчас. Так что я толку не вижу ни от одного варианта, ни от второго. 🤷♀️
Такой вариант сильно более ограниченный, т.к. требует создавать значение на каждой итерации
С чего это он требует? В моём примере вон не создаётся. Вообще не очевидно, зачем крутить цикл N раз, чтобы создать одно новое значение?
В твоём примере создаётся копия i. Если бы хотелось вернуть условный String, или impl Trait это было бы проблемой. > зачем крутить цикл N раз, чтобы создать одно новое значение? Потому что у нас императивный язык с состояние может меняться между итерациями
Вот поскольку язык императивный, мы сравнительно редко создаём новые значения, и часто переиспользуем уже существующие, в особенности — в циклах. 😊
?... Предлагаемый вами вариант while/else требует move возвращаемого значения каждую итерацию
Это ж смотря что возвращается. 🤷♀️ Можно же и ссылки возвращать. Хотя как на это посмотрит borrow checker — вопрос интересный! 😃
какая разница, будет мув ссылки
Он бесплатный. 😊
Да, но не всегда можно вернуть ссылку. Может быть нужно вернуть владение объектом созданным в цикле, например. А если ссылку возвращать, то она объект блокирует, что в цикле может вызывать проблемы.
Так это всё работает так же как сейчас, нет? 😊
Мы обсуждаем не реализованную фичу, сейчас её вообще нет
Ну и я утверждаю, что она будет работать так же плохо, как то, что уже есть. 😂
Уже несколько лет пишу код в основном на Python, видел использование этого только в коде чувака, который любил переусложнять код.
В итоге зря спорили, походу, label_break_value вполне покрывает все требуемые удобства.
ы, всегда забываю что это существует
в целом правильно написали. Используйте итераторы. И ждите негативных гвардов
Циклы должны делать то что нельзя удобно сделать в комбинаторах. Примеры как у чувака совсем не воодушевляют на реализацию
Итераторы частный случай, сообщению сто лет, label_break_value - прекрасная, почти готовая альтернатива
Обсуждают сегодня