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

у структуру данных в Rust. Он содержитVec пар ключ-значение. При вставке в структуру мне нужно найти соответствующий ключ и обновить как ключ, так и значение (которое на самом деле является дочерним указателем). Код выглядит примерно так, гдеpivots этоref mut вVec<Pivot> а такжеPivot это просто структура с двумя полями:

match pivots.iter_mut().find(|ref p| key <= p.min_key) { // first mutable borrow
    Some(ref mut pivot) => {
        // If there is one, insert into it and update the pivot key
        pivot.min_key = key;
        pivot.child.insert(key, value) // recursive call
    },
    // o/w, insert a new leaf at the end
    None => pivots.push(Pivot /* ... */) // second mutable borrow
}

Но есть проблема. Даже если я не использую изменяемый итератор во втором ответвленииmatch, заемщик жалуется, что я не могу заимствовать*pivots как изменяемые более одного раза за один раз ".

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

match pivots.iter_mut().find(|ref p| key <= p.min_key) {
    Some(ref mut pivot) => {
        pivot.min_key = key;
        pivot.child.insert(key, value);
        return
    },
    None => ()
};
pivots.push(Pivot /* ... */)

но это кажется трудным для понимания, особенно когда это означает разбиение этого кода на его собственную функцию, чтобы позволитьreturn, Есть ли более идиоматический способ выполнить операцию обновления или вставки?

Ответы на вопрос(1)

«Нелексические времена жизни» который решает это в долгосрочной перспективе. Используя нелексические времена жизни в Rust 2018, доступные в Rust 1.31, ваш код работает как есть:

Игровая площадка

use std::collections::HashMap;

pub struct Pivot {
    pub min_key: u64,
    pub child: HashMap<u64, ()>,
}

fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
    match pivots.iter_mut().find(|ref p| key <= p.min_key) {
        Some(pivot) => {
            // If there is one, insert into it and update the pivot key
            pivot.min_key = key;
            pivot.child.insert(key, value);
            return;
        }
        // o/w insert a new leaf at the end
        None => {
            let mut m = HashMap::new();
            m.insert(key, value);
            pivots.push(Pivot {
                min_key: key,
                child: m,
            });
        }
    }
}

fn main() {
    let mut pivots = Vec::new();
    update_or_append(&mut pivots, 100, ());
}

До Rust 2018 вы можете обойти это с некоторой дополнительной обработкой потока управления.

Вы могли бы сделать ваш матчbool значение, независимо от того, произошло обновление или нет, и иметь условный блок ниже, используя это значение для добавления. Я считаю целесообразным поместить логику «обнови или добавь» в отдельную функцию (используяreturn после обновления) более идиоматический подход:

Игровая площадка

use std::collections::HashMap;

pub struct Pivot {
    pub min_key: u64,
    pub child: HashMap<u64, ()>,
}

fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
    if let Some(pivot) = pivots.iter_mut().find(|ref p| key <= p.min_key) {
        // If there is one, insert into it and update the pivot key
        pivot.min_key = key;
        pivot.child.insert(key, value);
        return;
    }
    // otherwise insert a new leaf at the end
    let mut m = HashMap::new();
    m.insert(key, value);
    pivots.push(Pivot {
        min_key: key,
        child: m,
    });
}

fn main() {
    let mut pivots = Vec::new();
    update_or_append(&mut pivots, 100, ());
}

С помощьюbool чтобы отследить, произошло ли обновление:

Игровая площадка

use std::collections::HashMap;

pub struct Pivot {
    pub min_key: u64,
    pub child: HashMap<u64, ()>,
}

fn update_or_append(pivots: &mut Vec<Pivot>, key: u64, value: ()) {
    let updated = match pivots.iter_mut().find(|ref p| key <= p.min_key) {
        Some(pivot) => {
            // If there is one, insert into it and update the pivot key
            pivot.min_key = key;
            pivot.child.insert(key, value);
            true
        }
        // o/w insert a new leaf at the end below
        None => false,
    };
    if !updated {
        let mut m = HashMap::new();
        m.insert(key, value);
        pivots.push(Pivot {
            min_key: key,
            child: m,
        });
    }
}

fn main() {
    let mut pivots = Vec::new();
    update_or_append(&mut pivots, 100, ());
}
 Stefan22 нояб. 2017 г., 08:11
Это может быть моей ошибкой, что я часто пропускаю длинные тексты вопросов и не понимаю, что они уже содержат (нежелательный) ответ на вопрос. otoh ответы там не принадлежат, так что я не чувствую себя виноватым в этом случае. И я думаю, что отдельная функция на самом деле легче понять.
 user481516234222 нояб. 2017 г., 08:43
Не нужно вины, но это на самом деле не отвечает на вопрос ...
 user481516234221 нояб. 2017 г., 17:35
Опция отдельных функций уже рассматривается в вопросе. Может быть, ответ мог бы предоставить исходный код для первого предложенного решения, где соответствие создаетbool?

Ваш ответ на вопрос