没有malloc的no_std中的无堆链接列表

时间:2019-07-12 01:40:32

标签: linked-list rust

尝试无堆链接列表时缺少什么?

我的目标是获取以下代码以在堆栈上生成序列[1、2、3],然后将这些值打印在单独的行上,而不使用Box或需要堆的任何其他内容或stdmalloc

我浏览了https://rust-unofficial.github.io/too-many-lists,但是所有“好”列表似乎都取决于RcBox等。

heapless crate整洁,但需要事先知道列表的大小。

我的Google-fu不够强大,无法找到很多帮助。任何指针将不胜感激。但是,这就是我的想法:

struct Node<'a, T> {
    value: T,
    next: Option<&'a Node<'a, T>>
}

struct List<'a, T> {
    head: Option<&'a Node<'a, T>>,
    tail: Option<&'a Node<'a, T>>
}

impl<'a, T> List<'a, T> {
    fn new() -> Self {
        Self {
            head: None,
            tail: None
        }
    }

    fn push(self, value: T) ->Self {
        unimplemented!(); // What's missing here?
    }
}

struct Iter<'a, T> {
    next: Option<&'a Node<'a, T>>
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;

    fn next(&mut self) -> Option<&'a T> {
        match self.next.take() {
            Some(next) => {
                self.next = next.next;
                Some(&next.value)
            },
            None => None
        }
    }
}

impl<'a, T> IntoIterator for List<'a, T> {
    type Item = &'a T;
    type IntoIter = Iter<'a, T>;

    fn into_iter(self) -> Self::IntoIter {
        Iter {
            next: self.head
        }
    }
}

fn main() {
    let list = List::new();
    let list = list.push(1);
    let list = list.push(2);
    let list = list.push(3);
    for item in list {
        println!("{}", item);
    }
}

如您所见,我在尝试实现List.push时遇到了困难。

2 个答案:

答案 0 :(得分:1)

在不知道其大小(或至少其大小的上限)的情况下分配堆栈中的东西将对圆进行平方运算,将无法正常工作。您可以让编译器为您确定大小,但这差不多。原因很简单:堆栈分配可能不会失败,并且编译器必须确保所有内容都适合。

如果您想继续坚持使用push(T)签名,那么只取值Matt Thomas的答案就可以了。

这是我的问题,它避免了构建嵌套类型:

struct Node<'a, T> {
    value: T,
    next: Option<&'a Node<'a, T>>,
}

impl<'a, T> Node<'a, T> {
    pub fn new(value: T, next: Option<&'a Self>) -> Self {
        Node { value, next }
    }

    pub fn iter(&'a self) -> Iter<'a, T> {
        Iter {
            current: Some(self),
        }
    }
}

struct Iter<'a, T> {
    current: Option<&'a Node<'a, T>>,
}

impl<'a, T> Iterator for Iter<'a, T> {
    type Item = &'a T;
    fn next(&mut self) -> Option<&'a T> {
        match self.current {
            Some(Node { value, next }) => {
                self.current = *next;
                Some(value)
            }
            None => None,
        }
    }
}

fn main() {
    // Allocation of the Nodes directly on the stack,
    // not inside a push method. <= Solves lifetime issues
    // Reversed order solves mutability issues.
    let three = Node::new(3, None);
    let two = Node::new(2, Some(&three));
    let one = Node::new(1, Some(&two));

    for item in one.iter() {
        println!("{}", item)
    }
}

答案 1 :(得分:0)

这里是一个无栈的堆栈,可以完成OP中所述的目标:

https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=fb26b12270bd0a523a693276ec36014f

#[derive(Debug)]
struct Cons<T, U>(T, U);

#[derive(Debug)]
struct MyOption<T>(Option<T>);

trait Push<T>: Sized {
    fn push(self, value: T) -> Cons<Self, T>;
}

impl<T, U> Push<U> for Cons<T, U> {
    fn push(self, value: U) -> Cons<Self, U> {
        Cons(self, value)
    }
}

impl<T> Push<T> for T {
    fn push(self, value: T) -> Cons<Self, Self> {
        Cons(self, value)
    }
}

impl<T: Iterator<Item = U>, U> Cons<T, MyOption<U>> {
    fn next(&mut self) -> Option<U> {
        match (self.1).0.take() {
            Some(u) => Some(u),
            None => self.0.next()
        }
    }
}

impl<T> Iterator for Cons<MyOption<T>, MyOption<T>> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        match (self.1).0.take() {
            Some(t) => Some(t),
            None => (self.0).0.take()
        }
    }
}

impl<T: Iterator<Item = U>, U> Iterator for Cons<Cons<T, MyOption<U>>, MyOption<U>> {
    type Item = U;
    fn next(&mut self) -> Option<Self::Item> {
        match (self.1).0.take() {
            Some(u) => Some(u),
            None => self.0.next()
        }
    }
}

impl<T> Iterator for MyOption<T> {
    type Item = T;
    fn next(&mut self) -> Option<Self::Item> {
        self.0.take()
    }
}

fn create_stack() -> impl Iterator<Item = i32> + core::fmt::Debug {
          MyOption(Some(0))
    .push(MyOption(Some(1)))
    .push(MyOption(Some(2)))
    .push(MyOption(Some(3)))
    .push(MyOption(Some(4)))
}

fn main() {
    let stack = create_stack();
    println!("Here's the stack:");
    println!("{:?}", stack);

    println!("Here are the items in reverse order");
    for item in stack {
        println!("{}", item);
    }
}

输出:

Here's the stack:
Cons(Cons(Cons(Cons(MyOption(Some(0)), MyOption(Some(1))), MyOption(Some(2))), MyOption(Some(3))), MyOption(Some(4)))
Here are the items in reverse order
4
3
2
1
0

注意事项

  • 您无法循环执行stack = stack.push(...)(因为stack.push(...)返回不同的类型)
  • 我根本不考虑Drop的行为。我想这将是递归的,并且对于大堆栈来说会很麻烦
  • 这可以创建巨大结构。尽量不要让它们过分移动
  • 是否有一种方法可以创建不需要Iterator结构来容纳Cons类型的Option?并且可以多次迭代的方法吗?也许
  • 我怀疑这些隐式函数中的每一个对于结果堆栈中的每个元素都是重复的(因为每个元素的类型不同且所有函数都是通用的)
  • 每次调用.push()都可能会复制self(这与Copy特征不同,但在Rust中,Rust可以在幕后做memcpy作为所有权移动以使事情保持整洁”