Search code examples
rustrust-cargo

Lifetimes for String slices


I'm going through the rust black book and it mentions lifetime elision rules, and how especially for functions inputting and returning &str (strings stored on the stack), don't need explicit lifetimes. My question is why did they do so in the first place. The way I've been visualizing a string in rust is somewhat like a slice that the variable now holds. Is that incorrect?

        let mut s = String::from("alfdj");
        let k = &s[0..1];
        let s = "laskjd";
        println!("{}",k);`

This is what I tried and what confused me about the relationship between the string s and the slice k. I redefine s and it has no effect on k which is why I thought the &str k became independent of the string s.


Solution

  • This is a concept known as variable shadowing. Whenever you define a variable using let or let mut, you are creating a new variable which happens to have the same variable name. The old variable still exists but cannot be accessed through its name. This is part of the notion of lexical scoping. Your code snippet is equivalent to the following:

    let mut s = String::from("alfdj");
    let k = &s[0..1];
    let w = "laskjd";
    println!("{}",k);
    

    Here, we just replaced the second s with w.

    The same thing happens when you call a function. For example, in the code

    fn scoping() -> i32 {
       let x = 3;
       let g = |mut x| {
          x += 1;
          x
       };
       g(x) + x // evaluates to 7; calling g(x) doesn't change x
    }
    

    there are two different variables, both named x. Similarly, we can have the following occur:

    let x = 3;
    {
       let x = 4;
       println!("{}", x); // 4
       let x = "abc";
       println!("{}", x); // abc
    }
    println!("{}", x); // 3