update: Thanks to all the reply, I finally realized that there are more approaches to deal with the question that I thought a while-else
is the most beautiful solution.
Same topic is discussion one or even more years before this thread:
before this thread, the main voice is that, there is no necessary using while-else
, and some technical issues prevent else
from adding to the main Rust language.
But several days before, I met the question where a while-else
is useful:
what I wrote and some accept answers are quite ugly without while-let statement:
//what I wrote
impl Solution {
pub fn find_content_children(mut g: Vec<i32>, mut s: Vec<i32>) -> i32 {
let mut ans=0;
g.sort_unstable();
s.sort_unstable();
let mut g=g.into_iter();
let mut s=s.into_iter();
while let Some(g)=g.next(){
while let Some(s)=s.next(){
if g<=s{ans+=1;break}
}
// if s.next() is none, there is no necessary to check the rest elements in the outer loop
}
ans
}
}
// other accepted answer
impl Solution {
pub fn find_content_children(mut g: Vec<i32>, mut s: Vec<i32>) -> i32 {
g.sort();
s.sort();
let mut i = 0;
let mut j = 0;
while i < g.len() && j < s.len() {// if g is short and s is long, and most of elements in s smaller than it is in g, we have to perform much useless check for the statement `i < g.len()`
if g[i] <= s[j] {
i += 1;
}
j += 1;
}
i as i32
}
}
//using a while-else (or whatever) structure, the answer will be more beautiful:
impl Solution {
pub fn find_content_children(mut g: Vec<i32>, mut s: Vec<i32>) -> i32 {
let mut ans=0;
g.sort_unstable();
s.sort_unstable();
let mut g=g.into_iter();
let mut s=s.into_iter();
while let Some(g)=g.next(){
while let Some(s)=s.next(){
if g<=s{ans+=1;break}
}else{// if `s.next()` is `None`
break//break the outer loop
}
}
ans
}
}
some discussion tried make the for statement return a Option<T>
, it is quite easy using break Some(x)
or break true /*if we don't care about the return value*/
instead.
other idea,let var = while
BOOL else EXPR { BLOCK }may distinguish the confusing of
while COND{BLOCK}else{EXPR}`
I tried a similar syntax,
while let Some(s)=s.next() || {break}{//the `||` is treated as an operator rather than a closure
//means while (cond) or {break, or other leagal statement that generate `!` or `false`}
//no more mislead will generate since the meaning of `||` is fixed.
...
}
but failed to compile since current syntax does not support let-chains.
Currently, to my best knowledge, the only solution is using label to simulate while-else without extra cost:
'outer: while let Some(g)=g.next(){
loop {if let Some(s)=s.next(){
if g<=s{ans+=1;break}
}else{break 'outer}}
}
but I do not think labels are the final solution since label is more flexible and may bring extra errors.