2014-11-25 4 views
3

This question связаны, однако в большей степени, охватывает причину почему компилятор не может вывести безопасный срок службы при возврате изменяемых ссылок из Iterator::next, который я думаю, я понимаю.Простой, как возможный пример возвращения изменяемой ссылки с вашего собственного итератора

Мой вопрос:

Какие конкретные шаги вы можете предпринять при проектировании собственный итератор так, что он может производить изменяемые ссылки? В конечном счете, я надеюсь на краткий, по возможности, пошаговый, комментарий к примеру как Iterator, так и его next, которые я (и любой) могут использовать в качестве четкой ссылки, когда они сталкиваются с этой ситуацией. unsafe примеры в порядке, я думаю, они, вероятно, необходимы!

ПРИМЕЧАНИЕ: Я понимаю, что MutItems обычно является рекомендуемым примером, однако его выполнение может быть сложно выполнить, поскольку нет никакой документации по 1. Как маркеры работают в этой ситуации и 2. Что расширяет макрос iterator! до и как это работает. Если вы используете MutItems в качестве своего примера, пожалуйста, проясните это?

Спасибо!

+1

Параметр 'iterator' макрос просто немного раньше, в файле: http://doc.rust-lang.org/src/core/home/rustbuild/src/rust-buildbot/slave/nightly- linux/build/src/libcore/slice.rs.html # 1042-1105 –

ответ

4

Вот способ использования изменяемого итератора над гипотетической структурой Point. Обратите особое внимание на большой комментарий, который я надел в блок unsafe. Я нахожу это очень полезен для комментирования каждого блока unsafe аналогичным образом, так как я только стреляю себе в ногу, если я ошибаюсь!

use std::mem; 

#[derive(Debug)] 
struct Point { 
    x: u8, 
    y: u8, 
    z: u8, 
} 

impl Point { 
    fn iter_mut(&mut self) -> IterMut { 
     IterMut { point: self, idx: 0 } 
    } 
} 

struct IterMut<'a> { 
    point: &'a mut Point, 
    idx: u8, 
} 

impl<'a> Iterator for IterMut<'a> { 
    type Item = &'a mut u8; 

    fn next(&mut self) -> Option<&'a mut u8> { 
     let retval = match self.idx { 
      0 => Some(&mut self.point.x), 
      1 => Some(&mut self.point.y), 
      2 => Some(&mut self.point.z), 
      _ => None 
     }; 

     if retval.is_some() { 
      self.idx += 1; 
     } 

     // This is safe because... 
     // (from http://stackoverflow.com/questions/25730586): 
     // The Rust compiler does not know that when you ask a mutable 
     // iterator for the next element, that you get a different 
     // reference every time and never the same reference twice. Of 
     // course, we know that such an iterator won't give you the 
     // same reference twice. 
     unsafe { mem::transmute(retval) } 
    } 
} 

fn main() { 
    let mut p1 = Point { x: 1, y: 2, z: 3 }; 

    for x in p1.iter_mut() { 
     *x += 1; 
    } 

    println!("{:?}", p1); 
} 
+1

Спасибо! В итоге я сделал это в своем собственном случае. Для любого, кто не уверен в том, что делает «трансмутация», вот краткое описание его поведения [из документов] (http://doc.rust-lang.org/std/mem/fn.transmute.html), «Непосредственно преобразует значение одного типа в значение другого типа ». В этой ситуации трансмутация выводит правильный тип возвращаемого значения, гарантируя при этом проверку заимствования, что изменчивый заем безопасен. – mindTree

 Смежные вопросы

  • Нет связанных вопросов^_^