2017-11-20 1 views
1

녹에 데이터 구조를 쓰고 있습니다. 여기에는 Vec 키 - 값 쌍이 포함되어 있습니다. 구조체에 삽입 할 때 일치하는 키를 찾고 키와 값 (실제로는 자식 포인터)을 업데이트해야합니다.Vec에서 업데이트 또는 삽입하는 방법?

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 
} 

그러나 문제가있다 : 코드는 pivotsref mutVec<Pivot>에와 Pivot 두 개의 필드가 단지 구조체이다이 같은 비트를 보인다. 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

이 작업을 수행하는 가장 좋은 방법은 반복자 대신 색인을 사용하는 것입니다.

match pivots.iter().position(|ref p| key <= p.min_key) { 
    Some(i) => { 
     // If there is one, insert into it and update the pivot key 
     let pivot = &mut pivots[i]; 
     pivot.min_key = key; 
     pivot.child.insert(key, value) 
    }, 
    // o/w, insert a new leaf at the end 
    None => pivots.push(Pivot /* ... */) 
} 

이렇게하면 iter_mut 일 필요가 없습니다. iterator 대신 명시 적 인덱스를 사용하기 때문에이 대안에 대해서는 여전히 만족스럽지 않습니다. 이것은 Vec에 대해서는 문제가 없지만 O (1) 임의 액세스 색인이없는 구조의 컨테이너에서는 작동하지 않습니다.

색인을 사용하지 않아도되는 다른 대답을 수락합니다.

2

이 문제를 장기적으로 해결해야하는 병합 된 RFC "non-lexical lifetimes" (tracking issue)이 있습니다. 지금은 몇 가지 추가 제어 흐름 처리로 해결할 수 있습니다.

업데이트가 발생했는지 여부와 상관없이 일치하는 값을 bool으로하고 해당 값을 사용하여 추가 할 조건 블록을 아래에 추가 할 수 있습니다. 야간 기능 nll (진행중인 작업을 사용

Playground

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,()); 
} 

: 나는 더 관용적 접근 방식을 (업데이트 후 return를 사용하여) 별도의 함수로 "업데이트 또는-APPEND"논리를 넣어 고려 "비 어휘 수명")에 대한 원래의 코드는 이미 작동합니다 :

Playground

#![feature(nll)] 
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,()); 
} 
,369 bool을 사용하여 1,363,210은

업데이트가 발생 여부를 추적 :

Playground

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,()); 
} 
+0

별도의 기능 옵션은 이미 문제의 고려된다.아마도 첫 번째 제안 된 솔루션에 대한 소스 코드를 제공 할 수있을 것입니다. 일치하는 부분이 'bool'을 생성합니까? – user4815162342

+0

나는 종종 질문에서 긴 텍스트를 건너 뛰고 그들이 질문에 대한 (원하지 않는) 대답을 이미 포함하고 있다는 것을 깨닫지 못한다는 것은 내 실수 일 수 있습니다. 귀찮은 답변은 거기에 속하지 않으므로 나는이 사건에 대해 죄책감을 느끼지 않습니다. 그리고 저는 별도의 기능이 실제로 더 이해하기 쉽다고 생각합니다. – Stefan

+0

죄책감은 필요 없지만 실제로 질문에 답변하지 않습니다 ... – user4815162342

관련 문제