可以在表达式中组合赋值和比较吗?

时间:2016-11-03 09:16:14

标签: rust flow-control

在C中,通常在单个表达式中分配和比较:

n = n_init;
do {
    func(n);
} while ((n = n.next) != n_init);

据我所知,这可以用Rust表示:

n = n_init;
loop {
    func(n);
    n = n.next;
    if n == n_init {
        break;
    }
}

其作用与C版本相同(假设循环体不使用continue)。

在Rust中有更简洁的表达方式,还是上面的理想示例?

就本问题而言,假设所有权或满足借阅检查程序不是问题。由开发人员来满足这些要求。

例如,作为整数:

n = n_init;
loop {
    func(&vec[n]);
    n = vec[n].next;
    if n == n_init {
        break;
    }
}

这似乎很明显,Rust的例子是惯用的Rust - 但是我希望将这种循环风格转移到Rust,我很想知道是否有更好/不同的方式来表达它

3 个答案:

答案 0 :(得分:6)

在Rust中表示迭代的惯用方法是使用Iterator。因此,您将实现一个执行n = n.next的迭代器,然后使用for循环迭代迭代器。

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)
        }
    }
}

它留给读者一个练习,让这个迭代器能够从第一个元素开始,而不是从第二个元素开始。

答案 1 :(得分:2)

Rust支持ifwhile中的模式匹配:

  • 而不是具有布尔条件,如果模式匹配
  • ,则认为测试成功
  • 作为模式匹配的一部分,您将绑定与名称匹配的值

因此,如果不是建立一个布尔条件,而是构建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;
    }
}

但是,如果您可以使用Iterator,那么您将更加惯用。

答案 2 :(得分:0)

Rust中的分配返回空元组。如果您适合使用非惯用的代码,则可以将赋值结果与一个空的元组进行比较,并使用逻辑连接来链接您的实际循环条件。

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
  

这具有一个缺点,即进入循环需要运行逻辑(可以使用C的do {..} while();样式循环来避免这种情况)。

您可以在do-while宏中使用此方法,但是可读性不是那么好,因此重构可能更可取。无论如何,这就是它的外观:

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

这是宏的代码:

macro_rules! do_it {
    ($b: block while $e:expr) => {
        loop {
            $b
            if !($e) { break };
        }
    }
}