You deleted your follow-up question, here's an answer anyways:
Edit: Now the question is below this answer ^^
So the expression A(String::from("1")).get()
, which is syntactic sugar for A::get(&A(String::from("1")))
, contains the sub-expression &A(String::from("1"))
, which creates a reference to A(String::from("1"))
. This expression is not referring to any existing place (like e.g. a variable, or a field), so it creates new, temporary place to put the value for you. This is called a "temporary", those are like implicitly created anonymous variables that live for the duration of one statement.
The whole statement here is something like
let value = A(String::from("1")).get();
right after that statement, the temporary would be dropped, the method get
couples the lifetime of the returned &u32
to the lifetime of the &A
that's passed in, so the borrow checker disallows any further use of value
after this let
statement. What the implementation of get
actually does doesn’t really matter, because functions are checker (mostly) independently in Rust, just based on the signature of other functions. (This is great for API stability and for local reasoning.)
This is the "normal" case, and naively it would happen for the example of
let value = A().get();
too. But this case can be made work anyways by constant promotion, which basically turns your code into
const PROMOTED: &'static A = &A();
let value = PROMOTED.get();
Most restrictions for when this can happen are the same restriction for when the respective const
declaration would be accepted in the first place (i.e. it needs to be constructable at compile-time, which rules out functions like String::from
; it cannot have interior mutability of be a &mut _
reference. There's the additional restriction that nothing must happen when dropping the variable, so that this transformation doesn't change behavior, even when it's applied to code that would've compiled successfully without the constant promotion (otherwise someone who expects the drop code to run at the end of the statement could rightfully complain about unexpected compiler behavior). This last restriction can actually be circumvented if you write the const
yourself, and this way "opt out" of expecting any drop behavior. E.g. something like
// snippet 3, modified
struct A(String);
impl A {
fn get(&self) -> &u32 {
&1
}
}
const C: &'static A = &A(String::new());
let value = C.get();
println!("{}", value);
does actually work. Of course in this concrete example, using an ordinary local variable would be fine, too, and more lightweight syntactically, as well as more flexible with what kind of String
values you may create.
The &1
in your code examples is also an example of const promotion, but it's unrelated to the reason why some snippets compiled an others didn't.