Possible to combine assignment and comparison in an expression?

白昼怎懂夜的黑 提交于 2019-12-02 02:15:18

The idiomatic way to represent iteration in Rust is to use an Iterator. Thus you would implement an iterator that does the n = n.next and then use a for loop to iterate over the iterator.

struct MyIter<'a> {
    pos: &'a MyData,
    start: &'a MyData,
}
impl<'a> Iterator for MyIter<'a> {
    type Item = &'a MyData;
    fn next(&mut self) -> Option<&'a MyData> {
        if self.pos as *const _ == self.start as *const _ {
            None
        } else {
            let pos = self.pos;
            self.pos = self.pos.next;
            Some(pos)
        }
    }
}

it is left as an exercise to the reader to adapt this iterator to be able to start from the first element instead of starting from the second.

Rust supports pattern matching in if and while:

  • instead of having a boolean condition, the test is considered successful if the pattern matches
  • as part of pattern matching, you bind the values matched to names

Thus, if instead of having a boolean condition you were building an Option...

fn check(next: *mut Node, init: *mut Node) -> Option<*mut Node>;

let mut n = n_init;
loop {
    func(n);
    if let Some(x) = check(n.next, n_init) {
        n = x;
    } else {
        break;
    }
}

However, if you can use an Iterator instead you'll be much more idiomatic.

nyda

An assignment in Rust returns the empty tuple. If you are fine with non-idiomatic code you can compare the assignment-result with such an empty tuple and use a logical conjunction to chain your actual loop condition.

let mut current = 3;
let mut parent;

while (parent = get_parent(current)) == () && parent != current {
    println!("currently {}, parent is {}", current, parent);
    current = parent;
}

// example function
fn get_parent(x: usize) -> usize {
    if x > 0 { x - 1 } else { x }
}

// currently 3, parent is 2
// currently 2, parent is 1
// currently 1, parent is 0

This has the disadvantage that entering the loop needs to run logic (which you can avoid with C's do {..} while(); style loops).

You can use this approach inside a do-while macro, but readability isn't that great and at that point a refactoring might be preferable. In any case, this is how it could look:

do_it!({
    println!("{}", n);
} while (n = n + 1) == () && n < 4);

This is the code for the macro:

macro_rules! do_it {
    ($b: block while $e:expr) => {
        loop {
            $b
            if !($e) { break };
        }
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!