Save mutable link later, even when smoothed

I am trying to implement something like lightning, but I use mutable links to avoid having to deconstruct and restore the data structure when passing through it. I have some sample code for trying a linked list, although I would ideally like to apply it to other structures like trees.

pub enum List<T> {
    Empty,
    Cons { head: T, tail: Box<List<T>> },
}

pub struct Zipper<'a, T: 'a> {
    trail: Option<Box<Zipper<'a, T>>>,
    focus: &'a mut List<T>,
}

impl<'a, T: 'a> Zipper<'a, T> {
    pub fn down(&'a mut self) {
        match self.focus {
            &mut List::Empty => (),
            &mut List::Cons {
                tail: ref mut xs, ..
            } => {
                //We need a way to convince rust that we won't use oldZipper
                //until xs goes out of scope
                let oldZipper = std::mem::replace(
                    self,
                    Zipper {
                        trail: None,
                        focus: xs,
                    },
                );
                self.trail = Some(Box::new(oldZipper));
            }
        }
    }
}

Capturing a check does not suit this:

error[E0499]: cannot borrow `*self` as mutable more than once at a time
  --> src/main.rs:21:21
   |
16 |                 tail: ref mut xs, ..
   |                       ---------- first mutable borrow occurs here
...
21 |                     self,
   |                     ^^^^ second mutable borrow occurs here
...
30 |     }
   |     - first borrow ends here

This is not surprising: if we have a zipper focused on the list and calling on it down, we get a zipper with a mutable link to the tail of this list, so we have mutable smoothing.

, Zipper trail , focus , "" . : , , , .

? "" , , split_at: - , , trail , focus , ?

+6
1

Zipper. : , , , .

:

use std::mem;
use std::marker::PhantomData;

pub enum List<T> {
    Empty,
    Cons { head: T, tail: Box<List<T>> },
}

pub struct Zipper<'a, T: 'a> {
    trail: Option<Box<Zipper<'a, T>>>,
    focus: *mut List<T>,
    _list: PhantomData<&'a mut List<T>>,
}

impl<'a, T: 'a> Zipper<'a, T> {
    pub fn new(list: &'a mut List<T>) -> Zipper<'a, T> {
        Zipper {
            trail: None,
            focus: list as *mut List<T>,
            _list: PhantomData,
        }
    }

    pub fn down(&mut self) {
        unsafe {
            match *self.focus {
                List::Empty => (),
                List::Cons {
                    tail: ref mut xs, ..
                } => {
                    let old_zipper = mem::replace(
                        self,
                        Zipper::new(xs),
                    );
                    self.trail = Some(Box::new(old_zipper));
                }
            }
        }
    }
}

fn main() {
    let mut list = List::Cons { head: 1, tail: Box::new(List::Empty) };
    let mut zipper = Zipper::new(&mut list);
    zipper.down();
    zipper.down();
}

focus Zipper *mut List<T>. , . Zipper::down. _list PhantomData<&'a mut List<T>>. PhantomData - , ", / T, " ". , 'a .

, Zipper::new &'a mut List<T> : Zipper , , List<T>, , , . , Zipper List; List, Zipper List , , List .


, Zipper. , , , , . :

impl<'a, T: 'a> Zipper<'a, T> {
    pub fn focus(&mut self) -> &'a mut List<T> {
        unsafe { &mut *self.focus }
    }
}

a &'a mut List<T>, , . , self, , focus, List<T>. &'a mut List<T> Zipper, , &'a mut List<T> ( unsafe, ). :

impl<'a, T: 'a> Zipper<'a, T> {
    pub fn focus(&mut self) -> &mut List<T> {
        unsafe { &mut *self.focus }
    }
}

, Zipper , &mut List<T>, , focus ( down) , &mut List<T> .

+3

All Articles