Home > other >  Rust reference of string literal behaves differently when I use in single function or only in main f
Rust reference of string literal behaves differently when I use in single function or only in main f

Time:01-17

I am learning ownership and lifetime recently. But I find a weird situation about string literal.

//! work perfectly

fn foo() -> &'static str {
    let a = "66";
    &a
}

fn main() {
    let b = foo();
    println!("{}", b);
}

When I use string literal like above, it works perfectly.But when I use it like the following:

//! broken

fn main() {
    {
        let b;
        {
            let a = "66";
            b = &a;
        }
        println!("{}", b);
    }
}

It was broken and tell me that:

b = &a;
    ^^ borrowed value does not live long enough

These make me confused. Why are they different?

Please help me and thanks a lot.

CodePudding user response:

The difference between the two programs comes from auto-dereferencing.

//! work perfectly

fn foo() -> &'static str {
    let a = "66";
    &a // the type of this expression is not &'static str it is &&'static str
}

fn main() {
    let b = foo();
    println!("{}", b);
}

Since the type of a is &'static str the type of &a is &&'static str. Note the second reference. It is the reference to the string that does not have static lifetime, not the string value. However, since foo has a return type of &'static str, &a is auto-dereferenced to a and the type of b is inferred to be &'static str. In the second program this does not happen as the type is not explicit, so b is inferred to be a &&'static str which is referencing a reference which only lives for the life of the block.

If the second program is updated to explicitly declare b's type, you would get the same effect.

However, the better approach would to not rely on auto dereferencing at all, and use one of the following two programs:

fn foo() -> &'static str {
    let a = "66";
    a // note no &
}

fn main() {
    let b = foo();
    println!("{}", b);
}

Or

fn main() {
    {
        let b;
        {
            let a = "66";
            b = a; // Again no &
            // In idiomatic code it would probably make sense to inline the
            // assignment, but I have left it in for clarity with the original code
        }
        println!("{}", b);
    }
}
  •  Tags:  
  • Related