比较列表中的所有元素,并获取匹配对的可变引用

时间:2018-12-12 20:42:44

标签: loops rust iterator borrow-checker borrowing

我的目标是根据某些条件将列表中的每个元素与列表中的每个其他元素进行比较。在伪代码中,类似:

for i, x in list.enumerate():
    for y in list[i..]:
        if x.match(y):
            // Modify both x and y

我想获得每个匹配对中两个项目的可变引用。事实证明这很困难。根据{{​​3}},获取对列表中多个项目的可变引用的最佳方法是通过this answer。我编写了一个包装函数,用于提取对列表的两个可变引用:

/// Gets two mutable references to elements i and j in list
fn get_pair<'a, T>(i: usize, j: usize, list: &'a mut [T]) -> (&'a mut T, &'a mut T) {
    let (a, b) = list.split_at_mut(j);

    let first = &mut a[i];
    let second = &mut b[0];

    (first, second)
}

但是,我仍然无法在嵌套的for循环中使用此功能而不破坏借用规则:

for stuff1 in list.iter() {
    // immutable borrow on list here
    for stuff2 in list[i..].iter() {
        if stuff1.compare(stuff2) {
            let (stuff1, stuff2) = get_pair(i, j, list); // mutable borrow on list
            do_something(stuff1, stuff2);
        }
    }
}

相反,我保存一对匹配的索引,然后在另一个循环中实际获取元素并对其进行处理。

// Find matching pairs and push their indices
let mut matches: Vec<(usize, usize)> = Vec::new();
for (i, stuff1) in list.iter().enumerate() {
    for (j, stuff2) in list[i..].iter().enumerate() {
        if stuff1.compare(stuff2) {
            matches.push((i, j));
        }
    }
}

// Get two mutable references by indices from list
for m in matches.iter() {
    let (i, j) = m;
    let (stuff1, stuff2) = get_pair(*i, *j, list);
    do_something(stuff1, stuff2);
}

这可行,但似乎有点复杂。有没有更简单或更简单的方法可以在不违反借阅规则的情况下实现这一目标?

理想情况下,我想在原始循环中修改匹配对,而无需单独的循环来遍历索引。

可以在split_at_mut上找到我当前代码的完整示例。

1 个答案:

答案 0 :(得分:2)

您可以这样操作,并生成相当不错的代码:

let mut list = [1, 2, 3];
for i in 0..list.len() {
    let (a, b) = list.split_at_mut(i);
    let item_b = &mut b[0];
    for item_a in a {
        println!("{} {}", item_a, item_b);
    }
}

此处的关键是0..len迭代避免将list锁定为只读。 split_at_mut向借阅检查器证明,两个引用都不能指向同一元素。