Who owns the box on the heap?

I am studying Rust right now. I want to test my understanding of property in rust. I get confused with the concepts of ownership and borrowing in a recursive structure. I see this code at rustbyexample.com

// Allow Cons and Nil to be referred to without namespacing
use List::{Cons, Nil};

// A linked list node, which can take on any of these two variants
enum List {
    // Cons: Tuple struct that wraps an element and a pointer to the next node
    Cons(u32, Box<List>),
    // Nil: A node that signifies the end of the linked list
    Nil,
}

// Methods can be attached to an enum
impl List {
    // Create an empty list
    fn new() -> List {
        // `Nil` has type `List`
        Nil
    }

    // Consume a list, and return the same list with a new element at its front
    fn prepend(self, elem: u32) -> List {
        // `Cons` also has type List
        Cons(elem, Box::new(self))
    }

    // Return the length of the list
    fn len(&self) -> u32 {
        // `self` has to be matched, because the behavior of this method
        // depends on the variant of `self`
        // `self` has type `&List`, and `*self` has type `List`, matching on a
        // concrete type `T` is preferred over a match on a reference `&T`
        match *self {
            // Can't take ownership of the tail, because `self` is borrowed;
            // instead take a reference to the tail
            Cons(_, ref tail) => 1 + tail.len(),
            // Base Case: An empty list has zero length
            Nil => 0
        }
    }

    // Return representation of the list as a (heap allocated) string
    fn stringify(&self) -> String {
        match *self {
            Cons(head, ref tail) => {
                // `format!` is similar to `print!`, but returns a heap
                // allocated string instead of printing to the console
                format!("{}, {}", head, tail.stringify())
            },
            Nil => {
                format!("Nil")
            },
        }
    }
}

fn main() {
    // Create an empty linked list
    let mut list = List::new();

    // Append some elements
    list = list.prepend(1);
    list = list.prepend(2);
    list = list.prepend(3);

    // Show the final state of the list
    println!("linked list has length: {}", list.len());
    println!("{}", list.stringify());
}

How to visualize a stack and a bunch of this code?

From what I learned, I prependget ownership of the list, allocate space in the heap, and translate the list into the heap. When it prependfinishes, it moves (gives ownership) the newly created list to an external variable.

Is this visualization correct?

The first list is :: new return Nil, so the stack will contain Nil.

After executing list.prepend (1), Nil will be on the heap at the address 0x0000 (assumption), Cons (1,0x0000) will enter the stack.

list.prepend(2) Cons (1,0x0000) 0x00002 (), Cons (2,0x0002).

, list.prepend(3) Cons (2,0x0002), 0x00004 (), Cons (3,0x0004).

Cons (1,0x0000)? Is Cons (2,0x0002) Cons (1,0x0000)? ?

, , , Rust , . ?

+4
1

Box<Foo> Foo - , Box.

, , :

let list = Cons(3, Box::new(Cons(2, Box::new(Cons(1, Box::new(Nil))))))
  • list list, Cons , u32 3 Box<List>
  • Box<List> list: a Cons, 2, Box<List>
  • Box<List> list: a Cons, 1 Box<List>
  • Box<List> list: a Nil.

, Box Box es, Box , , , , , .

+3

All Articles