-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lifetime complaints depend on whether you attach the value to a variable first #48998
Comments
That's an intended result of static rvalue promotion. With that, a |
Oh I see, because: fn foo_me<'a>() -> Foo<'a> {
static BAR: Bar = Bar {
val: 42
};
Foo {
bar: &BAR
}
} Also works. I wonder if it's possible to improve the error message to make this clearer. I realise we can't have every edge case documented there though, then it would make it less clear. |
I feel that the first case should emit a warning about lifetime |
It's also worth mentioning that if the compiler fails to elide[1] the lifetime to static for another reason (eg the value is not allowed to be static because it's a trait or in its instantiation you're calling a function) it just silently doesn't work. So if you add this: impl Bar {
fn new(val: i32) -> Bar {
Bar {
val: val
}
}
} And then try to do this: fn foo_me<'a>() -> Foo<'a> {
Foo {
bar: &Bar::new(42)
}
} You get the error about borrowing that we got with the To a noob this rule in general seems really confusing, and involves you knowing all the compiler rules involved to understand why your code doesn't compile (as opposed to the error clearly explaining what you did wrong, because it's not that the borrowed value won't live long enough, it's actually because it couldn't elide it to static). [1] Rust's usage of this word really confuses me, but that's neither here nor there |
You could read it as "ensures it outlives/outlasts"/"lives long enough to survive X". Any suggestions on how to improve the wording, not only the diagnostic themselves, to make the subject friendlier to newcomers are welcome. After a while when you understand the concept is very hard to un-understand it to see the failings with fresh eyes :-/ |
@estebank to me elide means to omit something. So when people talk about lifetime elision, it sounds like removing lifetimes? But I think it's actually about adding implicit lifetimes? Or converting lifetimes? I think a specific section in the handbook on what that word means would be really helpful. I imagine it's too late to change the word. I realise there is this:
I find my flow for confusion is:
I have read the chapter on lifetimes but I really feel like I need to read it 2-3 more times. My background is completely in memory-safe languages, which may make the concept more complicated for me. It would be really cool if there was some kind of site / git repo where you progressively solve problems that are caused by lifetimes, borrowing, and generally more esoteric Rust concepts that people from major languages aren't used to. Sort of like 4clojure / project euler but specifically to get people comfortable with layering all of these techniques on top of each other. |
@SCdF I think https://github.com/carols10cents/rustlings is meant to be something like this, though it hasn't made it to the "esoteric" parts of Rust yet. |
Yep I have these links queued up:
Hopefully enlightenment will be in there somewhere. Ideally though, Rust's documentation itself would contain this kind of thing, as it would be more discoverable, and if getting being noob friendly is important then I think that's critical |
The diagnostics for the two examples mentioned are much nicer now after #59114: Original case#[derive(Debug)]
struct Foo<'a> {
bar: &'a Bar
}
#[derive(Debug)]
struct Bar {
val: i32
}
fn main() {
let foo = foo_me();
println!("{:?}", foo);
}
fn foo_me<'a>() -> Foo<'a> {
let bar = Bar {
val: 42
};
Foo {
bar: &bar
}
}
Case from comments#[derive(Debug)]
struct Foo<'a> {
bar: &'a Bar
}
#[derive(Debug)]
struct Bar {
val: i32
}
impl Bar {
fn new(val: i32) -> Bar {
Bar {
val: val
}
}
}
fn foo_me<'a>() -> Foo<'a> {
Foo {
bar: &Bar::new(42)
}
}
I've made a new issue (#120344) for the suggestion in #48998 (comment). It doesn't seem to me like there's much actionable left here, so I think this should be closed. |
Closing this as it is completed and we have #120344 to track the related changes |
(Apologies if this is just me misunderstanding Rust, I'm very new to the language.)
Given:
The following implementation of
foo_me
works:While this one doesn't:
With:
I can see what it's complaining about, but I feel like these two examples should function identically. I have a more complicated piece of code that I'm not smart enough to coerce into the working format, so there may be more complicated variants on this which are not solvable.
The text was updated successfully, but these errors were encountered: