Право собственности на ржавчину - не может двигаться из-за того, что находится «за общей ссылкой» - PullRequest
1 голос
/ 09 апреля 2020

Я изучаю Rust и тренируюсь на связанных списках, в результате чего я хочу найти решение, которое не включает .clone() в конце.

Вот самый маленький полезный код MVP, который я могу придумать ( Rust Playground ):

#![allow(unused)]
fn main() {
    let v: Option<Box<ListNode>> = None;

    println!("{:?}", v);
    let result2 = get_nth_node(v, 3);
    println!("  --> {:?}", result2);
}

#[derive(PartialEq, Eq, Clone, Debug)]
pub struct ListNode {
    pub val: i32,
    pub next: Option<Box<ListNode>>
}

fn get_nth_node(head: Option<Box<ListNode>>, n:usize) -> Option<Box<ListNode>> {
    if head.is_none() {
        return None;
    }

    let mut count = 1;
    let mut ptr: &Option<Box<ListNode>> = &head;
    while count < n {
        count += 1;
        match ptr {
            None                    => return None,
            Some(v) => ptr = &v.next
        }
    }
    return (*ptr);
}

Это приводит к ошибке при перемещении и заимствовании:

error[E0507]: cannot move out of `*ptr` which is behind a shared reference
  --> src/main.rs:30:12
   |
30 |     return (*ptr);
   |            ^^^^^^
   |            |
   |            move occurs because `*ptr` has type `std::option::Option<std::boxed::Box<ListNode>>`, which does not implement the `Copy` trait
   |            help: consider borrowing the `Option`'s content: `(*ptr).as_ref()`

Я понимаю, почему изменение функции для возврата (*ptr).clone() работает, но это кажется излишним.

Мои два основных вопроса: 1. Что конкретно представляет собой общее упоминание, за которым стоит *ptr? 2. Есть ли лучший концептуальный способ работы с этим в Rust?

1 Ответ

0 голосов
/ 09 апреля 2020

Что конкретно является общей ссылкой, за которой стоит * ptr?

ptr является общей (неизменной) ссылкой:

let mut ptr: &Option<Box<ListNode>> = &head;

*ptr стоит за этой ссылкой.

Есть ли лучший концептуальный способ работы с этим в Rust?

Ну, вы можете просто не работать со ссылками, так как вы берете список по значению и, следовательно, используете его:

fn get_nth_node(mut head: Option<Box<ListNode>>, n:usize) -> Option<Box<ListNode>> {
    let mut count = 1;
    while count < n {
        count += 1;
        match head {
            None                    => return None,
            Some(v) => head = v.next
        }
    }
    return head;
}

В качестве альтернативы, вы можете работать с ссылками (что вероятно, это была бы лучшая идея):


fn get_nth_node(mut head: Option<&ListNode>, n:usize) -> Option<&ListNode> {
    let mut count = 1;
    while count < n {
        count += 1;
        match head {
            None                    => return None,
            Some(v) => head = v.next.as_ref().map(Box::as_ref)
        }
    }
    head
}
...