Circular linked list on Rust

I want to write a cyclic singly linked list. But the problem is that when creating the first element, it must refer to itself. I seem to have heard that to do this, you need to wrap in Pin. but it didn't help. how can this be implemented?

struct node {
    data:i32,
    next: Option<Pin<Box<node>>>
}

struct List {
    frist: Box<node>,
    last: Box<node>
}

fn create_list(data:i32) {
    let mut node = Box::new(node{ data, next: None });
    let pin = Pin::new(node);
    node.next = Some(pin);
}

Mistake:

error[E0382]: assign to part of moved value: `*node`

     let mut node = Box::new(node { data, next: None });
         -------- move occurs because `node` has type `std::boxed::Box<node>`, which does not implement the `Copy` trait
     let pin = Pin::new(node);
                        ---- value moved here
     node.next = Some(pin);
     ^^^^^^^^^ value partially assigned here after move
 2
Author: Ainar-G, 2020-04-22

2 answers

The problem with all connected lists in Rust, except for the simplest singly connected one , is that the ownership relationship between the elements is undefined. The entire list owns the elements, but it does not have a pointer to each element of the list - therefore, the standard container for the element is not selected.

The container should be the entire list, and the only normal way to make such a container is unsafe and raw pointers:

struct Node<T> {
    data: T,
    next: *mut Self,
}

struct List<T> {
    first: *mut Node<T>
}

fn create_list<T>(data: T) -> List<T> {
    unsafe {
        let node = Node { data, next: std::ptr::null_mut() };
        let node_ptr = Box::into_raw(Box::new(node));
        (*node_ptr).next = node_ptr;
        List { first: node_ptr }
    }
}

And don't forget to write a destructor for the list:

impl<T> Drop for List<T> {
    fn drop(&mut self) {
        unsafe {
            let head = self.first;
            if head.is_null() { return; }

            let mut node = head;
            loop {
                let next = (*node).next;
                Box::from_raw(node);
                node = next;
                if node == head { break; }
            }
        }
    }
}

I did not run the code, so please treat it as a draft, and correct the errors if any are noticed.

 0
Author: Pavel Mayorov, 2020-04-29 09:52:14

Try cloning it or passing it by link.


use std::pin::Pin;

#[derive(Clone)]
struct Node {
    data:i32,
    next:Option<Pin<Box<Node>>>
}
#[derive(Clone)]
struct List {
    frist: Box<Node>,
    last: Box<Node>
}

fn create_list(data:i32) {
    let mut node = Box::new(Node{data,next: None});
    let a = node.clone();
    node.next = Some(Pin::new(a));
}

fn main () {

create_list(4);

}
 -2
Author: Wooh, 2020-04-22 07:45:36