5 ms·
You don't have to go as far as doubly-linked list. Writing a simple cons-list is hard enough: enum List<T> { Nil, Cons(T, Box<List<T>>)
by GreaterFool 9y ago
You don't have to go as far as doubly-linked list. Writing a simple cons-list is hard enough:
enum List<T> {
Nil,
Cons(T, Box<List<T>>)
}
Imagine you're writing `Iterator`. You have a `&mut List<T>`. For `Nil`, you're done. For `Cons`, you take it apart, return the `T`, deref the `Box` and move your `&mut List<T>` to point to that value. Nothing could be easier, right?
Except in Rust you can't do that! One can resort to unsafe code or use ugly and inefficient workarounds to remain in safe-land.
- anaphylactic 9y agoI don't understand what your concern is - this only took me about a minute to write and it looks completely safe and efficient. https://play.rust-lang.org/?gist=674f4b88876614f603fd70368cb6a067&version=stable https://play.rust-lang.org/?gist=674f4b88876614f603fd70368cb...
- GreaterFool 9y agoThanks for this snippet. Didn't think about that. If I understand correctly that's overly restrictive though. You're limiting the lifetime of list elements to the lifetime of the spine of the list. What I want is this: enum List<T> { Nil, Cons(T, Box<List<T>>) } struct IntoIter<T>(List<T>); impl<T> IntoIterator for List<T> { type Item = T; type IntoIter = IntoIter<T>; fn into_iter(self) -> Self::IntoIter { IntoIter(self) } } impl<T> Iterator for IntoIter<T> { type Item = T; fn next(&mut self) -> Option<T> { match std::mem::replace(&mut self.0, List::Nil) { List::Nil => None, List::Cons(x, l) => { std::mem::replace(&mut self.0, *l); Some(x) } } } } But without the `replace` calls. Also, in general I may be working with a data type for which I don't have a value I can conjure out of thin air (like `Nil`). What then?