Understanding Rust Lifetimes

preview_player
Показать описание
In this stream we attempt to discuss one example that can challenge even long time Rustaceans when it comes to understanding lifetimes. Follow along as we dive deep into lifetimes. If you understand this code, then you're well on your way to understanding almost any Rust related lifetime code out in the wild.

Рекомендации по теме
Комментарии
Автор

Ok, it took me a bit to understand why the std::mem::replace method works. So here is how I see it:

Normally, element is a mutable reference to self.slice[0]. This mutable reference has lifetime 'next, because it is defined within the next function that has a lifetime of 'next. We need to make it have a lifetime of 'iter instead. The only mutable reference to self.slice with a lifetime of 'iter is self.slice itself.

So when you do 'let slice = &mut self.slice;', you are creating a mutable reference to self.slice, with lifetime 'next since it is defined in the next function. Then std::mem::replace takes that mutable reference with lifetime 'next, **dereferences** it and sees a mutable reference to self.slice with lifetime 'iter, and returns it to us which is exactly what we want. It is the fact that it dereferences the 'dest' function parameter and returning it (with the lifetime associated with it) which makes it work.

-I think it would have been a bit clearer if at --1:06:23--, you would have used 'let slice2 = std::mem::replace(slice, &mut []);' because it is a bit confusing when you see that slice is being replaced with '&mut []', and it's old value is being bound to slice again.- You did this as 1:08:26, I should have watched it through before commenting!

I had to draw it out to see how it worked, but I'm glad I did because I think I get it now :D

Oguz
Автор

For the longest time I kept thinking, "who is this know-it-all Chad fella? And why is he asking all the questions?"!! 🤦🏽‍♂️
Love the content.

Amapramaadhy
Автор

TIL (finally) why you have to annotate lifetimes and generic parameters twice in the impl signature!

Thank you Ryan again for the awesome tutorial!

albertlee
Автор

56:40 I think it comes down to a simple fact. If the data is guaranteed to exist (immutably), and it won't be changed ever (because we enforced mutable borrow laws, so you can't read the data after it has been mutably borrowed), and because we know how long the data will last for (up to the highest lifetime), then because of all these conditions, we can say for certain that the data referenced there will ALWAYS be the same, so it is safe to lengthen it to the longest lifetime in that case (regardless that it was borrowed as 'next). I suppose that in this case, the reference from 'next effectively == 'a

aqua
Автор

Your content really is the best. Thank you. I’m totally inspired.

kevinbatdorf
Автор

I really like your instruction style, Ryan; thanks for doing this.

@35:30 I think the question was this:
If I write a function that returns an iterator, should the function signature specify the concrete iterator type that is returned, or should it use "impl Iterator"? And the answer, I believe, is that in general it is better to use "impl Iterator."

To be more precise about it,
fn foo<T>(...) -> impl Iterator<Item = T> {...}
is better than
fn foo<T>(...) -> MyIterator<T> {...}

It is better in that it preserves flexibility in the implementation -- later you might want to return some other type. If all you promised was that you would return SOMETHING that implements Iterator, then you can make that change. If you promised that you would return a MyIterator, then changing that would be a breaking change in your API.

ClearerThanMud
Автор

C & C++ Programmers would be like, ow this is much easier. people coming from GC language " what the heck have i been watching for an hour "

serakshiferaw
Автор

Finally I found someone discussing Lifetimes up to advance usage. Ive been struggling to understand lifetimes.

j-p-d-e-v
Автор

This is amazing. I finally understand something of Lifetime. Your content is gold! :D

nickx
Автор

This is by far the best video about Rust lifetime. thank you so much. Would be great if you can post more videos about Rust like async 😊

anthonylee
Автор

Thanks Ryan. As always, very insightful.
48:48, did you mean "we can't have multiple 'writers' at the same time?" (i heard 'readers')

vikramfugro
Автор

A totally underrated guy. Thank you, Ryan!

konstantinta
Автор

1:07:37 Isn't it a bit better to use std::mem::take() instead? You're replacing it with a default, and take() should do just that

aqua
Автор

Hey, I got a question: isn't it weird that we can std::mem::replace effectively self.slice temporarily with &mut []? AFAIK shouldn't any contents of self.slice need to have a lifetime of 'iter (which is clearly not the case with &mut [], which should live on the function stack)? Is this just a special elision trick where the compiler proves that self.slice is never actually invalid or am I missing something?

naturallyinterested
Автор

This is great content! Please keep it up. I don't spend much time on twitch but will start to try and watch you live

andydataguy
Автор

I haven't written a line of rust yet (cant figure out a project to do) but it would seem that, in the first iteration of the Iterator implementation where you check if the slice.is_empty and return none, that code could panic with a index out of bounds/range "exception" when self.slice has a single item in it. (Unless slice[1..] returns differently than i would expect.)

edit
I would also like to note that I appreciate it when you repeat the questions from chat (which you have done consistently throughout this and other videos).

Baremutation
Автор

Where you said that T must live as long as struct, that literally made this make more sense than all the countless guides I read

25:00 "it's more code" \*ends up being less code\*

megumin
Автор

You can move out of self.slice directly by passing &mut self.slice into std::mem::replace(). No need for a placeholder borrow. Thanks for another great stream Ryan, do you know if there’s work being done to make forwarding of lifetimes like this easier?

NILOCOgov
Автор

Thank you, Ryan. You are really good at explaining Rust. Your voice is awesome, too.

milesjackson
Автор

BTW, your cursor is black against black - it was very hard to see when you were point out items in the code.

FreemanPascal