在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,我很想知道是否有更好/不同的方式来表达它
答案 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支持if
和while
中的模式匹配:
因此,如果不是建立一个布尔条件,而是构建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 };
}
}
}