Pregunta No se puede mover fuera del contenido prestado al hacer coincidir una enumeración


Estoy tratando de imprimir un árbol (es un LinkedList Ahora mismo, pero eso será arreglado):

use std::io;
use std::rc::Rc;

enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) };

    let mut current = root;
    while true {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(next) => {
                current = *next;
            }
            NodeKind::Leaf => {
                break;
            }
        }
    }

    let mut reader = io::stdin();
    let buff = &mut String::new();
    let read = reader.read_line(buff);
}

El compilador dice:

error[E0507]: cannot move out of borrowed content
  --> src/main.rs:24:27
   |
24 |                 current = *next;
   |                           ^^^^^ cannot move out of borrowed content

Sólo estoy leyendo el valor, no cambiando nada. Estoy asignando un valor de una referencia a otro valor, tratando de desreferir un Rc<T> valor y almacenarlo en un local mut variable.

tal vez algo como esto puede funcionar:

while true {
    println!("{}", current.value);
    match &current.kind {
        &NodeKind::Branch(next) => {
            current = next;
        }
        &NodeKind::Leaf => {
            break;
        }
    }
}

o tal vez

let mut current = &Rc::new(root);
while true {
    println!("{}", current.value);
    match current.kind {
        NodeKind::Branch(next) => {
            current = &next;
        }
        NodeKind::Leaf => {
            break;
        }
    }
}

pero obtengo el mismo error más 'next' does not live long enough


5
2018-05-21 05:11


origen


Respuestas:


No hay necesidad de clonar aquí, es absolutamente posible hacer lo que quiere lograr con referencias:

use std::rc::Rc;

enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(Rc::new(branch)) };

    let mut current = &root;
    loop {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(ref next) => {
                current = &**next;
            }
            NodeKind::Leaf => break,
        }
    }
}

Los únicos cambios importantes de su código son que el patrón en el partido es ref next y current es de tipo &Node.

ref los patrones unen sus variables por referencia, es decir, next tiene tipo &Rc<Node>. Llegar &Node de él, necesita desreferenciarlo dos veces para obtener Node y luego hacer referencia nuevamente para obtener &Node. Debido a las coerciones de Deref, también es posible escribir current = &next, y el compilador insertará un número apropiado de *s para usted automáticamente.

También cambié de while (true) a loop Porque es más idiomático y ayuda al compilador a razonar sobre tu código.

Todos los cruces de estructuras similares a árboles se hacen así en Rust. ref los patrones permiten no salir de las variables, lo que es absolutamente necesario cuando solo necesita leer datos. Puede encontrar más información sobre patrones y cómo interactúan con la propiedad y los préstamos. aquí.


7
2018-05-21 08:01



El error se muestra porque de manera predeterminada match realizará un movimiento.

Después de mover un valor (es decir, no se tomó por referencia o método que toma self se llamó) las llamadas subsiguientes fallan. Es probable que necesite clonar, que es una propiedad tanto de su struct y enum ausencia. Una vez que agregue esos (#[derive(Clone)) y cambio current = *next; dentro current = (*next).clone();, tu programa funcionará nuevamente!

use std::io;
use std::rc::Rc;

#[derive(Clone)]
enum NodeKind {
    Branch(Rc<Node>),
    Leaf,
}

#[derive(Clone)]
struct Node {
    value: i32,
    kind: NodeKind,
}

fn main() {
    let leaf = Node { value: 10, kind: NodeKind::Leaf };
    let branch = Node { value: 50, kind: NodeKind::Branch(std::rc::Rc::new(leaf)) };
    let root = Node { value: 100, kind: NodeKind::Branch(std::rc::Rc::new(branch)) };

    let mut current = root;
    while true {
        println!("{}", current.value);
        match current.kind {
            NodeKind::Branch(next) => {
                current = (*next).clone();
            }
            NodeKind::Leaf => {
                break;
            }
        }
    }

    let reader = io::stdin();
    let buff = &mut String::new();
    let read = reader.read_line(buff);
}

Patio de recreo

Si tu let mut current = &root entonces puedes evitar clone() según la respuesta de Vladimir a continuación (Parque infantil de la versión de Vladimir.)


2
2018-05-21 06:22



No puedo resolver el problema con 1) todavía, pero encontré una respuesta para 2).

En la parte superior, necesitas usar:

use std::rc::Rc;

en lugar de

use std::rc;


1
2018-05-21 06:04