Search code examples
rustlinked-listborrow-checker

Constructing cons list from slices


Reading the book, I was trying to add methods to the "cons-list" type, defined as

enum List<T> {
   Item(T, Box<List<T>>),
   Null,
}

The first method I tried to implement was from_slice which build a cons list from &[T]. However the borrow-checker does not accept the following implementation

impl<T> List<T> {
    
    pub fn from_slice(v: &[T]) -> List<T> 
    where T: Copy 
    {
        let n = v.len();

        let lst = List::Null;

        for i in (0..n).rev() {
            let lst = List::Item(v[i], Box::new(lst));
        }

        lst
    }
}

Why is this not accepted and what should I do to convince the borrow checker that this program is safe?

Interestingly expanding the above for loop does not give any compilation error (the borrow checker likely realizes that the previous lst is being shadowed after each line).

// Expanding the previous function for v = [0, 1, 2]
let lst = List::Null;
let lst = List::Item(0, Box::new(lst));
let lst = List::Item(1, Box::new(lst));
let lst = List::Item(2, Box::new(lst));

Solution

  • By doing let lst = ... inside the for loop, you're creating a new lst binding which is immediately dropped after that line. What you want instead is to make the lst one level up mut and re-assign to that:

    impl<T> List<T> {
        pub fn from_slice(v: &[T]) -> List<T>
        where
            T: Copy,
        {
            let n = v.len();
    
            let mut lst = List::Null;
    
            for i in (0..n).rev() {
                lst = List::Item(v[i], Box::new(lst));
            }
    
            lst
        }
    }
    

    Playground