代码之家  ›  专栏  ›  技术社区  ›  rap-2-h

将对结构属性的引用绑定到返回可变引用[duplicate]的函数内的变量

  •  1
  • rap-2-h  · 技术社区  · 7 年前

    #[derive(Debug)]
    struct Node {
        value: String,
    }
    
    #[derive(Debug)]
    pub struct Graph {
        nodes: Vec<Box<Node>>,
    }
    
    fn mk_node(value: String) -> Node {
        Node { value }
    }
    
    pub fn mk_graph() -> Graph {
        Graph { nodes: vec![] }
    }
    
    impl Graph {
        fn add_node(&mut self, value: String) {
            if let None = self.nodes.iter().position(|node| node.value == value) {
                let node = Box::new(mk_node(value));
                self.nodes.push(node);
            };
        }
    
        fn get_node_by_value(&self, value: &str) -> Option<&Node> {
            match self.nodes.iter().position(|node| node.value == *value) {
                None => None,
                Some(idx) => self.nodes.get(idx).map(|n| &**n),
            }
        }
    }
    
    
    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn some_test() {
            let mut graph = mk_graph();
    
            graph.add_node("source".to_string());
            graph.add_node("destination".to_string());
    
            let source = graph.get_node_by_value("source").unwrap();
            let dest = graph.get_node_by_value("destination").unwrap();
    
            graph.add_node("destination".to_string());
        }
    }
    

    ( playground )

    这有错误

    error[E0502]: cannot borrow `graph` as mutable because it is also borrowed as immutable
      --> src/main.rs:50:9
       |
    47 |         let source = graph.get_node_by_value("source").unwrap();
       |                      ----- immutable borrow occurs here
    ...
    50 |         graph.add_node("destination".to_string());
       |         ^^^^^ mutable borrow occurs here
    51 |     }
       |     - immutable borrow ends here
    

    这个例子来自 和我的非常相似,但它很管用:

    pub struct Queue {
        older: Vec<char>,   // older elements, eldest last.
        younger: Vec<char>, // younger elements, youngest last.
    }
    
    impl Queue {
        /// Push a character onto the back of a queue.
        pub fn push(&mut self, c: char) {
            self.younger.push(c);
        }
    
        /// Pop a character off the front of a queue. Return `Some(c)` if there /// was a character to pop, or `None` if the queue was empty.
        pub fn pop(&mut self) -> Option<char> {
            if self.older.is_empty() {
                if self.younger.is_empty() {
                    return None;
                }
    
                // Bring the elements in younger over to older, and put them in // the promised order.
                use std::mem::swap;
                swap(&mut self.older, &mut self.younger);
                self.older.reverse();
            }
    
            // Now older is guaranteed to have something. Vec's pop method // already returns an Option, so we're set.
            self.older.pop()
        }
    
        pub fn split(self) -> (Vec<char>, Vec<char>) {
            (self.older, self.younger)
        }
    }
    
    pub fn main() {
        let mut q = Queue {
            older: Vec::new(),
            younger: Vec::new(),
        };
    
        q.push('P');
        q.push('D');
    
        assert_eq!(q.pop(), Some('P'));
        q.push('X');
    
        let (older, younger) = q.split(); // q is now uninitialized.
        assert_eq!(older, vec!['D']);
        assert_eq!(younger, vec!['X']);
    }
    
    0 回复  |  直到 8 年前
        1
  •  38
  •   Shepmaster Tim Diekmann    7 年前

    A MCVE 你的问题可以归结为:

    fn main() {
        let mut items = vec![1];
        let item = items.last();
        items.push(2);
    }
    
    error[E0502]: cannot borrow `items` as mutable because it is also borrowed as immutable
     --> src/main.rs:4:5
      |
    3 |     let item = items.last();
      |                ----- immutable borrow occurs here
    4 |     items.push(2);
      |     ^^^^^ mutable borrow occurs here
    5 | }
      | - immutable borrow ends here
    

    你遇到了 这种锈是用来防止的。您有一个指向向量的引用,并试图插入到该向量中。这样做可能需要重新分配向量的内存,从而使任何现有引用失效。如果发生这种情况,并且您在 item ,则访问未初始化的内存,可能导致崩溃。

    在这个 凯斯,你实际上没有用 项目 (或 source

    fn main() {
        let mut items = vec![1];
        {
            let item = items.last();
        }
        items.push(2);
    }
    

    《铁锈2018》不再需要这个把戏了,因为 non-lexical lifetimes 已实现,但基础限制仍然存在-当存在对同一事物的其他引用时,不能有可变引用。这是一个 rules of references 覆盖 Rust编程语言 . 修改后的示例仍不能与NLL一起使用:

    let mut items = vec![1];
    let item = items.last();
    items.push(2);
    println!("{:?}", item);
    

    在其他情况下,可以复制或克隆向量中的值。该项将不再是引用,您可以根据需要修改向量:

    fn main() {
        let mut items = vec![1];
        let item = items.last().cloned();
        items.push(2);
    }
    

    如果类型不可克隆,可以将其转换为引用计数值(例如 Rc Arc )然后就可以克隆了。您可能也可能不需要使用 interior mutability

    struct NonClone;
    
    use std::rc::Rc;
    
    fn main() {
        let mut items = vec![Rc::new(NonClone)];
        let item = items.last().cloned();
        items.push(Rc::new(NonClone));
    }
    

    这个来自Rust编程的例子非常相似

    不,不是,因为它根本不使用引用。

    另请参见

        2
  •  3
  •   Shepmaster Tim Diekmann    8 年前

    这将结束块后的借用。

    #[cfg(test)]
    mod tests {
        use super::*;
    
        #[test]
        fn some_test() {
            let mut graph = mk_graph();
    
            graph.add_node("source".to_string());
            graph.add_node("destination".to_string());
    
            {
                let source = graph.get_node_by_value("source").unwrap();
                let dest = graph.get_node_by_value("destination").unwrap();
            }
    
            graph.add_node("destination".to_string());
        }
    }
    
    推荐文章