Rust 是否可以在表达式中组合赋值和比较?

Rust 是否可以在表达式中组合赋值和比较?,rust,control-flow,Rust,Control Flow,在C语言中,通常在单个表达式中赋值和比较: n = n_init; do { func(n); } while ((n = n.next) != n_init); 据我所知,这可以用锈表示为: n = n_init; loop { func(n); n = n.next; if n == n_init { break; } } 其工作原理与C版本相同(假设循环体不使用continue) 有没有更简洁的方法来表达这一点,或者上面的例子是理

在C语言中,通常在单个表达式中赋值和比较:

n = n_init;
do {
    func(n);
} while ((n = n.next) != n_init);
据我所知,这可以用锈表示为:

n = n_init;
loop {
    func(n);
    n = n.next;
    if n == n_init {
        break;
    }
}
其工作原理与C版本相同(假设循环体不使用
continue

有没有更简洁的方法来表达这一点,或者上面的例子是理想的

就本问题而言,假设所有权或满足借阅检查人的要求不是问题。满足这些要求取决于开发人员

例如,作为整数:

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

这似乎很明显,Rust示例是惯用的Rust—然而,我希望将这种风格的循环中的相当一部分转移到Rust,我想知道是否有更好/不同的方法来表达它。

在Rust中表示迭代的惯用方法是使用
迭代器。因此,您将实现一个迭代器,该迭代器执行
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)
        }
    }
}

struct MyIter Iterator for MyIter OptionRust支持
if
while
中的模式匹配:

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

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;
    }
}
fn检查(下一步:*mut节点,初始化:*mut节点)->选项;
设mutn=n_init;
环路{
func(n);
如果让一些(x)=检查(n.next,n_init){
n=x;
}否则{
打破
}
}

但是,如果您可以使用
迭代器
,您将更加习惯用法。

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

我会考虑把这个模式封装成迭代器,这样你就可以做一些类似的事情:<代码> > n,在某个ITER(NY-IIT){FUNC(n)}< /Cord>。每次发布代码片段时,我们都必须猜测所涉及的类型。他们是不是抄袭了?他们对某事有所有权吗?我们不知道!我们不知道@Matthieu M我感兴趣的是什么类型的流控制可以表达,我不想在我的问题中包含确切的类型,因为它会分散其他方面的注意力,而这部分我宁愿自己管理。这个问题被标记为:
寻求调试帮助的问题
,有人能解释为什么吗?-这是一个关于如何表达流控制的问题。这里没有需要调试的bug。@ideasman42:问题是这使得回答者的工作变得更加困难,因为所有权是生锈的核心概念,因此答案根据使用仿射类型、借用类型还是复制类型而有所不同。这就像你最后一个问题一样,当你在第一次回答
false
时添加了条件
test()
。。。如果这从一开始就被编码在代码中,我可能知道我的答案不合适。但由于我无法读懂你的心思,我提供了一个合适的答案,你在改变了问题之后,就不再合适了。所以请完成。虽然这很有趣(在某些情况下可能是一个很好的解决方案),但这读起来像是一个迂回的间接答案,它使流量控制变得不那么清晰,然后在达到初始值后就简单地中断。@ideasman42:完全同意,但如果您想在条件下赋值,这是我能想到的唯一模式(我不鼓励使用它)。这有一个缺点,即进入循环需要运行逻辑(使用C的
do{..}while();
style循环可以避免这种情况)。我已经用do更新了答案。。虽然是个例子,但现在你离常规还很远。
$b
中的
continue
语句将跳过最后一个中断。是的,根据你的问题,这是假设块中没有continue。如果你想避免这一点,你可能也可以ap$b在一个固定的单个或两个迭代循环中,并根据您在该循环中所做的其他分配,尝试判断是否使用了continue或break。
macro_rules! do_it {
    ($b: block while $e:expr) => {
        loop {
            $b
            if !($e) { break };
        }
    }
}