Две суммы Leetcode Rust Solution? - PullRequest
0 голосов
/ 03 января 2019

Я пытался использовать ржавчину, чтобы ответить на некоторые вопросы в leetcode.Пока мне сложно разобраться со связанным списком, особенно для вопроса Two Sum.Как мне справиться с проблемой перемещенного значения?

Этот кусок кода может пройти тест.

// Definition for singly-linked list.
// #[derive(PartialEq, Eq, Debug)]
// pub struct ListNode {
//   pub val: i32,
//   pub next: Option<Box<ListNode>>
// }
// 
// impl ListNode {
//   #[inline]
//   fn new(val: i32) -> Self {
//     ListNode {
//       next: None,
//       val
//     }
//   }
// }
pub fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
        let mut head1 = l1;
        let mut head2 = l2;
        let mut res = Some(Box::new(ListNode::new(0)));
        let mut tmp = &mut res;
        loop {
            let node1 = head1.take().unwrap_or(Box::new(ListNode::new(0)));
            let node2 = head2.take().unwrap_or(Box::new(ListNode::new(0)));
            tmp = match tmp.as_mut(){
                Some(_n) => {
                    let sum = node1.val + node2.val + _n.val;
                    let carry = sum /10;
                    _n.val = sum % 10;
                    if node1.next.is_none() && node2.next.is_none() && carry == 0{
                        return res;
                    } else {
                        _n.next = Some(Box::new(ListNode::new(carry)));
                    }
                    &mut _n.next
                }
                _ => unreachable!(),
            };
            head1 = node1.next;
            head2 = node2.next;
        }
    }

Пока он не может пройти локальную компиляцию, имея сообщение об ошибке

error[E0506]: cannot assign to `tmp` because it is borrowed
   --> empty.rs:109:13
    |
109 |               tmp = match tmp.as_mut(){
    |               ^           --- borrow of `tmp` occurs here
    |  _____________|
    | |
110 | |                 Some(_n) => {
111 | |                 let sum = node1.val + node2.val + _n.val;
112 | |                 let carry = sum /10;
...   |
121 | |                 _ => unreachable!(),
122 | |             };
    | |_____________^ assignment to borrowed `tmp` occurs here

error[E0499]: cannot borrow `*tmp` as mutable more than once at a time
   --> empty.rs:109:25
    |
109 |             tmp = match tmp.as_mut(){
    |                         ^^^ mutable borrow starts here in previous iteration of loop
...
126 |     }
    |     - mutable borrow ends here

error[E0505]: cannot move out of `res` because it is borrowed
   --> empty.rs:115:28
    |
105 |         let mut tmp = &mut res;
    |                            --- borrow of `res` occurs here
...
115 |                     return res;
    |                            ^^^ move out of `res` occurs here

Я подумал, что могу немного понять, поскольку tmp является изменяемой ссылкой на res, затем res перемещается.Но как я мог сохранить заголовок связанного списка, в то же время продолжая добавлять к нему хвосты?

1 Ответ

0 голосов
/ 03 января 2019

Ваш код компилируется так, как написано в стабильной версии Rust 2018 (или в ночной версии Rust 2015 с #![feature(nll)]).

Вы можете скомпилировать его в стабильной версии Rust 2015 с помощью нескольких настроек:

pub fn add_two_numbers(
    l1: Option<Box<ListNode>>,
    l2: Option<Box<ListNode>>,
) -> Option<Box<ListNode>> {
    let mut head1 = l1;
    let mut head2 = l2;
    let mut res = Some(Box::new(ListNode::new(0)));
    // Add this block to limit the scope of tmp.
    {
        let mut tmp = &mut res;
        loop {
            let node1 = head1.take().unwrap_or(Box::new(ListNode::new(0)));
            let node2 = head2.take().unwrap_or(Box::new(ListNode::new(0)));
            // Add braces around tmp to force it to be moved instead of reborrowed.
            tmp = match { tmp }.as_mut() {
                Some(_n) => {
                    let sum = node1.val + node2.val + _n.val;
                    let carry = sum / 10;
                    _n.val = sum % 10;
                    if node1.next.is_none() && node2.next.is_none() && carry == 0 {
                        // Move the return statement outside the block.
                        break;
                    } else {
                        _n.next = Some(Box::new(ListNode::new(carry)));
                    }
                    &mut _n.next
                }
                _ => unreachable!(),
            };
            head1 = node1.next;
            head2 = node2.next;
        }
    }
    return res;
}

Возможно, имеет смысл, почему return res необходимо вывести за пределы tmp. { tmp } вещь немного более запутанная: он говорит компилятору, чтобы переместить tmp вместо reborrowing его (см это объяснение )

.
...