Skip to content

Instantly share code, notes, and snippets.

@rylev
Created November 3, 2020 10:29
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rylev/3a3dd4b0d8563eb2267f489e559bb70e to your computer and use it in GitHub Desktop.
Save rylev/3a3dd4b0d8563eb2267f489e559bb70e to your computer and use it in GitHub Desktop.
Code for the Stream on Lifetimes (https://www.youtube.com/watch?v=MSi3E5Z8oRw)
struct MyIterator<'a, T> {
slice: &'a [T],
}
impl<'a, T> Iterator for MyIterator<'a, T> {
type Item = &'a T;
fn next<'next>(&'next mut self) -> Option<Self::Item> {
let (element, rest) = self.slice.split_first()?;
self.slice = rest;
Some(element)
// let element = self.slice.get(0);
// self.slice = &self.slice[1..];
// element
}
}
struct MyMutableIterator<'iter, T> {
slice: &'iter mut [T],
}
impl<'iter, T> Iterator for MyMutableIterator<'iter, T> {
type Item = &'iter mut T;
fn next<'next>(&'next mut self) -> Option<Self::Item> {
let slice1 = &mut self.slice;
let slice2 = std::mem::replace(slice1, &mut []);
let (first, rest) = slice2.split_first_mut()?;
self.slice = rest;
Some(first)
// // get first element
// let element = self.slice.get_mut(0);
// // set self.slice to the rest of the list
// self.slice = &mut self.slice[1..];
// // return first element
// element
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let mut collection = vec![1, 2, 3, 4];
let wrapper = MyIterator {
slice: &collection[..],
};
for (index, elem) in wrapper.enumerate() {
assert_eq!(*elem, collection[index]);
}
let mut collection = vec![1, 2, 3, 4];
let wrapper = MyMutableIterator {
slice: &mut collection[..],
};
for (index, elem) in wrapper.enumerate() {
*elem = *elem + 1;
}
assert_eq!(collection.get(0), Some(&2));
}
}
@hffmnn
Copy link

hffmnn commented Dec 10, 2021

Reading through the docs for std::mem::replace it states, that But replace can be used to disassociate the original value at that index from self, allowing it to be returned:. So I have one question left to understand the code:
In https://gist.github.com/rylev/3a3dd4b0d8563eb2267f489e559bb70e#file-iterator-rs-L27, what lifetime does the compiler think slice2 has? It's not 'next because we are disassociated from self. And why does it think that new lifetime is longer than 'next. Best would be in plain English 😄

@Kangaxx-0
Copy link

Reading through the docs for std::mem::replace it states, that But replace can be used to disassociate the original value at that index from self, allowing it to be returned:. So I have one question left to understand the code: In https://gist.github.com/rylev/3a3dd4b0d8563eb2267f489e559bb70e#file-iterator-rs-L27, what lifetime does the compiler think slice2 has? It's not 'next because we are disassociated from self. And why does it think that new lifetime is longer than 'next. Best would be in plain English 😄

The lifetime is 'a, that's the reason why this piece of code does the trick. let slice2 = std::mem::replace(slice1, &mut []); says - Instead of borrowing slice, I want to own it temporarily

@yanshay
Copy link

yanshay commented Oct 26, 2022

I think the below simplification is easier to understand the key point of this gist (and tested to work):

fn next(&mut self) -> Option<Self::Item> {
    let owned_slice_including_lifetime = std::mem::take(&mut self.slice);
    let (first, rest) = owned_slice_including_lifetime.split_first_mut()?;
    self.slice = rest;
    Some(first)
}

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