Thanks all for helps,
After reading the responses, as far as I understand, the problem is about "place/value expressions" and "temporary lifetimes". I just try to summary the details from responses.
First, String::from("abc")
, which is a value expression, needs a temporary location for its evaluation, as the reference says:
When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead...
The lifetime of this temporary location is the statement itself, but it would be "promoted" to the enclosing block by a let
, as the reference says:
When a temporary value expression is being created that is assigned into a let
declaration, however, the temporary is created with the lifetime of the enclosing block instead...
That may explain why
let abc = String::from("abc");
let s = s.as_str(); // or s: &str = s.as_ref()
compiles, but
let s = String::from("abc").as_str();
does not. It's because in the former, the lifetime of String::from("abc")
is promoted to the enclosing block thanks to let abc =
. However in the later, the temporary memory location is just passed into as_ref()
, the function cannot return a valid reference because the lifetime of the passed temporary memory is limited by the statement.
Note that the error comes from the trying to make a reference let s = ...
, if we do not do that, the following statement
String::from("abc").as_str();
compiles just fine.
Second, &String::from("abc")
, which is a place expression, still has a temporary location (there is no magic) but the location is "already promoted" by the borrow operator &
:
The left operand of ... is a place expression context, as is the single operand of a unary borrow
That means, &String::from("abc")
itself
... represents a memory location
whose lifetime is the enclosing block (!?), then there's no problem in passing it into the indexing operator [..]
.
Note that,
let s: &str = &String::from("abc")[..];
is actually
let s: &str = (&String::from("abc"))[..];
and not
let s: &str = &(String::from("abc")[..]);
I am still uncomfortable about the place expression, so correct me if I'm wrong.