Сравните все элементы в списке и получите изменяемые ссылки для соответствующих пар - PullRequest
0 голосов
/ 12 декабря 2018

Моя цель - сравнить каждый элемент в списке с каждым другим элементом в списке в соответствии с некоторыми критериями.В псевдокоде что-то вроде:

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

Я хотел бы получить изменяемую ссылку на оба элемента в каждой соответствующей паре.Это оказалось трудным.Согласно этому ответу , лучший способ получить изменяемые ссылки на несколько элементов в списке - через split_at_mut .Я написал функцию-обертку для извлечения двух изменчивых ссылок на список:

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

Это работает, но кажется слишком сложным.Есть ли более простой или более простой способ добиться этого без нарушения правил заимствования?

В идеале я хотел бы изменить совпадающие пары в исходном цикле, не нуждаясь в отдельном цикле для просмотра индексов.

Полный пример моего текущего кода можно найти на детской площадке .

1 Ответ

0 голосов
/ 13 декабря 2018

Вы можете сделать это следующим образом, и он генерирует довольно приличный код:

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 доказывает контролеру заимствований, что обе ссылки не могут указывать на один и тот же элемент.

...