Open mordrax opened 1 year ago
Hey! So there are actually a couple things going on here, apologies if this is unstructured; and also apologies if I over-explain things (if nothing else, hopefully I can point other people here with similar issues).
First: the example you gave actually isn't quite doing what you think it is. This is because i32
is a type which is Copy
.
Therefore, when you call drop(my_variable)
, you're actually copying my_variable
, and basically calling drop(7)
.
A code example which gets around this issue is:
#[derive(Debug)]
struct NotCopy {
i: i32
}
fn main() {
let mut my_reference: Option<&NotCopy> = None;
// Starting a scope.
{
// my_variable created // \ \
let my_variable: NotCopy = NotCopy { i : 7}; // | |
my_reference = Some(&my_variable); // | |- my_variable exists here. ('variable)
// At the end of the scope, `my_variable` is dropped // | |
drop(my_variable); // | |
// my variable destroyed // | /
// inner scope does not stop here }
// |
if let Some(reference) = my_reference { // |
println!("{reference:?}"); // |
} // /
} // inner scope now stops here
}
But what you'll see in this example is that we do run into an issue:
error[E0505]: cannot move out of `my_variable` because it is borrowed
--> src/main.rs:15:14
|
13 | my_reference = Some(&my_variable); // | |- my_variable exists here. ('variable)
| ------------ borrow of `my_variable` occurs here
14 | // At the end of the scope, `my_variable` is dropped // | |
15 | drop(my_variable); // | |
| ^^^^^^^^^^^ move out of `my_variable` occurs here
...
19 | if let Some(reference) = my_reference { // |
| ------------ borrow later used here
The error here is with the drop
, because that's the first point where rust can't figure out what to do: before that point, it's happy to give you a borrow of my_variable
, but at that point it's either got to move my_variable
, or let you keep that borrow (and since it can't do both, it's an error!).
I do think that the wording here could be improved, and I'm gonna have a think about how to do that (suggestions welcome) but before I do, I'd like to know if this explanation helped, or if there's something you're still confused about. That'll help me figure out what the best wording actually is!
Thanks for opening an issue!
Hey @tfpk , thanks for responding promptly!
I think I follow what you're getting at with drop
but it's raising more questions than it answers.
So reading 00_example, I chucked this into the playground and it works. ie, putting println! inside the inner scope, but after the drop prints 7 (https://play.rust-lang.org/?version=beta&mode=debug&edition=2021&gist=62de6293aff89f91d15e7d57b9446bce).
So now I'm confused about several things.
'static
lifetime?drop(my_variable)
differ from closing the scope { }
because in the playround, if I was to put the println! outside the scope, then it errors as expected, the compiler calls out that my_variable is no longer in scope at the time my_reference is being used in the println!, however, if the println!
is inside the scope { }
but after dropping my_variable
, it still works. so there's some differences there.main()
to the end, so perhaps this is rust jargon that I don't get yet, but my understanding is that the lifetime of 'variable
has to end later than the lifetime of the things that reference it, ie `'my_reference'I think there's two things here, a simpler explaination of lifetime and an accidental complexity introduced by this example. And we're now talking about both!
Sorry to pile on the confusion, let's try get it straightened out...
drop(my_variable)
(where my_variable
is Copy
) is identical to drop(my_variable.clone())
. That's what it means for a variable to be copy, and hopefully here you can see that it would mean that the drop
function basically has no effect.drop
does not cause the name to stop working, it simply moves the value. Drop is literally the function pub fn drop<T>(_x: T) { }
(i.e. it moves the value, then does nothing with it). This is the same as any moved value.To help with 1 and 2, the reading the documentation of the drop
function might help!
#[derive(Debug)]
struct NotCopy {
i: i32
}
fn main() {
let mut my_reference: Option<&NotCopy> = None; // lifetime of my_reference starts
let my_value: NotCopy = NotCopy { i: 8 }; // lifetime of my_value starts
my_reference = Some(&my_value);
if let Some(val) = my_reference {
println!("{val:?}");
}
}
Which seems to disprove my comment made in section 0. The trick here is that there are two seperate lifetimes which are being conflated here: the lifetime of my_reference
(the variable), and the lifetime of &my_value
(which is being stored inside my_reference
. The documentation kind of confuses the issue here (but I'm gonna have to think about how to fix it, because it's hard to say non-confusingly).
It is clear that the variables my_reference
and my_value
do not necessarily have to share a lifetime on their own. The trick is that &my_value
changes things: clearly, the reference &my_value
must have a smaller lifetime than my_value
(you can't get a reference to something before it exists, and Rust won't let you keep a reference around after the value being referenced is gone).
Okay I've had this checked; pretty sure it's all reasonable.
I've tried to improve the wording in #19, but it's a first draft which I'll have to revise again, I suspect.
Towards the end of the first chapter, once the
'variable
and'reference
lifetimes has been established, there is the following statement:The last part of this statement is confusing to me because it does not seem to be true for all cases.
Let's say in the code example, that the inner scope of
'variable
is expanded to include theif let
statement:It is not true that
'variable
is now larger than'reference
, because'reference
is declared earlier still.So this is confusing to me. It would make more sense if it read: