Mutating one field while iterating over another immutable field

后端 未结 3 886
执笔经年
执笔经年 2020-12-03 18:38

Given the following program:

struct Data {
    pub items: Vec<&\'static str>,
}

trait Generator {
    fn append(&mut self, s: &str) {
             


        
3条回答
  •  谎友^
    谎友^ (楼主)
    2020-12-03 19:17

    You can use RefCell:

    RefCell uses Rust's lifetimes to implement 'dynamic borrowing', a process whereby one can claim temporary, exclusive, mutable access to the inner value. Borrows for RefCells are tracked 'at runtime', unlike Rust's native reference types which are entirely tracked statically, at compile time. Because RefCell borrows are dynamic it is possible to attempt to borrow a value that is already mutably borrowed; when this happens it results in thread panic.

    use std::cell::{RefCell, RefMut};
    
    struct Data {
        pub items: Vec<&'static str>,
    }
    
    trait Generator {
        fn append(&self, s: &str) {
            self.output().push_str(s);
        }
    
        fn data(&self) -> &Data;
    
        fn generate_items(&self) {
            for item in self.data().items.iter() {
                match *item {
                    "foo" => self.append("it was foo\n"),
                    _ => self.append("it was something else\n"),
                }
            }
        }
    
        fn output(&self) -> RefMut;
    }
    
    struct MyGenerator<'a> {
        data: &'a Data,
        output: RefCell,
    }
    
    impl<'a> MyGenerator<'a> {
        fn generate(self) -> String {
            self.generate_items();
    
            self.output.into_inner()
        }
    }
    
    impl<'a> Generator for MyGenerator<'a> {
        fn data(&self) -> &Data {
            self.data
        }
    
        fn output(&self) -> RefMut {
            self.output.borrow_mut()
        }
    }
    
    fn main() {
        let data = Data {
            items: vec!["foo", "bar", "baz"],
        };
    
        let generator = MyGenerator {
            data: &data,
            output: RefCell::new(String::new()),
        };
    
        let output = generator.generate();
    
        println!("{}", output);
    }
    

    Rust playground

提交回复
热议问题