Skip to content

Conversation

@ABScripts
Copy link
Owner

No description provided.

}

/// iterates all nodes starting with this one and forward
/// Q: better rename this method to "iter" which seems to be Rust idiomatic name for returning iterator which iterates over value refs:

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the only reason we use iter_forward here is because we also should have iter_backward for the hardest tasks. when only one type of iterator is present - it should be iter()

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ack

* iter(), which iterates over &T.
* iter_mut(), which iterates over &mut T.
* into_iter(), which iterates over T. - this method is specifically used to convert collection into iterator (by moving ownership)
* Q: why does it consume collection?
Copy link

@MatrixDev MatrixDev Nov 3, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idomatically every into_* method should consume the receiver and receiver is Node<T> and not &Node<T>.

for example Vec has implementations for iterators in addition for iter and iter_mut:
image

now the question might be why do we even need iterator that consumes a collection - there are cases when we need to extract owned value of T from a collection while iterating. just as an example converting Vec<(String, User)> to HashMap<String, User>. it would not be possible with borrowing iterator or without cloning strings/users.

PS: there is also a concept of the lending iterator (GAT-based) but it is much more complex topic and requires very good understading of lifetimes and generics.

// We can also accept a collection here - that is why "I" MUST implement IntoIterator
let mut iter_i_swear = iter.into_iter();

// TODO: is that the right behaviour to panic if Iter is empty??

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any reason it should logically panic? why extending collection with empty collection is an error?

// Q: borrow chain?
// let mut cur_node = &mut collected_nodes;
// loop {
// // let Some(last_node) = &mut cur_node.next else { // but this would yield compiler error, why??

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

all of these can be used in let Some(_) but have a little different meaning:

&mut cur_node.next              // &mut Option<Box<Node<T>>>
cur_node.next.as_mut()          // Option<&mut Box<Node<T>>>
cur_node.next.as_deref_mut()    // Option<&mut Node<T>>

compiler will try to automatically implicitly dereference all patterns until they match. the difference that in first two cases it will be Some(&mut Box<Node<T>>) and in the last one Some(&mut Node<T>).

now ref is mostly a legacy syntax that moves reference from the right side to the left. let Some(ref value) means that value must be a reference (or mutable in your case) and compiler will try to find a pattern matching this requirement. ref is mostly not used anymore and it is often advised to use & or conversion functions (as_ref, as_mut, etc.) instead.

PS: outside of the let, Option<&T> is always preferred to &Option<T>. the only exception is &mut Option<T> when you actually want to modify the option itself and not the inner value. more objective benefit of Option<&T> is that its size will be 1*usize instead of 2*usize thanks to NPO (null pointer optimization).

}

// Q: What actually happens here when Box::new receives Node from "from_iter" method??
cur_node.next = Some(Box::new(Node::from_iter(iter.into_iter())));

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Node::from_iter return Node<T>, meaning struct itself is placed on the stack.
Box::new allocates buffer on the heap and moves this struct there.
in result you will have Box<Node<T>>.


pub fn remove_if<F>(self, mut closure: F) -> Option<Self>
where
F: Fn(&T) -> bool, // changed from "FnMut" -> "Fn"; seems to be saficient here

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it is sufficient here but usually libraries expose FnMut just in case called needs to modify something inside the closure. you can check iterator.filter(...) (or similar) as an example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants