Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics
Linux Systems
Linux Systems
Power Users
Power Users
Tabletop RPGs
Tabletop RPGs
Community Proposals
Community Proposals
tag:snake search within a tag
answers:0 unanswered questions
user:xxxx search by author id
score:0.5 posts with 0.5+ score
"snake oil" exact phrase
votes:4 posts with 4+ votes
created:<1w created < 1 week ago
post_type:xxxx type of post
Search help
Notifications
Mark all as read See all your notifications »
Q&A

Welcome to Software Development on Codidact!

Will you help us build our independent community of developers helping developers? We're small and trying to grow. We welcome questions about all aspects of software development, from design to code to QA and more. Got questions? Got answers? Got code you'd like someone to review? Please join us.

Post History

83%
+8 −0
Q&A What allows a string slice (&str) to outlive its scope?

tl;dr, the lifetime of "second" is static The heart of your confusion is this: Since we are taking a long-lived reference r to a string slice inner which is destroyed at the end of its scope, ...

posted 2y ago by Moshi‭  ·  edited 2y ago by Moshi‭

Answer
#2: Post edited by user avatar Moshi‭ · 2022-07-06T04:47:15Z (over 2 years ago)
  • ## tl;dr, the lifetime of `"second"` is `static`
  • The heart of your confusion is this:
  • > Since we are taking a long-lived reference r to a string slice inner which is destroyed at the end of its scope,
  • `inner` is gone at the end of its scope, yes. However, its *value* still lives on.
  • We have to think about the difference between *values* and *variables*. `r` doesn't reference `inner`, it references `"second"`. What's probably confusing you is that `inner` has a reference as its value.
  • ```rust
  • r = inner;
  • ```
  • This performs a copy of the value `inner`. We are **not** referencing `inner`. `"second"` is a string literal. It has a lifetime of `static`. After the assignment, the value of `r` is a `&'static str`. Indeed, we can actually just specify this and confirm that this compiles cleanly:
  • ```rust
  • let s: &'static str = "first";
  • let mut r: &'static str = s;
  • println!("First ref is {}", r);
  • {
  • let inner: &'static str = "second";
  • r = inner;
  • }
  • println!("Second ref is {}", r);
  • ```
  • If this still confuses you, let's work through a different example:
  • ```rust
  • let s = 1;
  • let mut r = s;
  • println!("First r is {}", r);
  • {
  • let inner = 2;
  • r = inner;
  • }
  • println!("Second r is {}", r);
  • ```
  • This should much more clearly show what's going on. We're just passing around values; who cares that `inner` dies at the end of its scope.
  • -----
  • I said at the beginning that
  • > `r` doesn't reference `inner`, it references `"second"`.
  • What would `r` referencing `inner` look like? Well, we'd borrow it instead of copying its value. (We also have to borrow `s` for parity)
  • ```rust
  • let s: &str = "first";
  • let mut r: &&str = &s;
  • println!("First ref is {}", r);
  • {
  • let inner: &str = "second";
  • r = &inner;
  • }
  • println!("Second ref is {}", r); // !!!!!
  • ```
  • ```
  • |
  • 7 | r = &inner;
  • | ^^^^^^ borrowed value does not live long enough
  • 8 | }
  • | - `inner` dropped here while still borrowed
  • 9 | println!("Second ref is {}", r); // !!!!!
  • | - borrow later used here
  • ```
  • As expected!
  • -----
  • This is getting kind of long, but on a final note, look at how this introduces a double reference. Let's think about lifetimes!
  • ```rust
  • let s: &str = "first"; // &'static str
  • let mut r: &&str = &s; // &'<s> &'static str
  • println!("First ref is {}", r);
  • {
  • let inner: &str = "second"; // &'static str
  • r = &inner; // &'<inner> &'static str
  • }
  • println!("Second ref is {}", r); // !!!!!
  • ```
  • For this purpose, `'<s>` means "has the same lifetime as `s`".
  • ## tl;dr, the lifetime of `"second"` is `static`
  • The heart of your confusion is this:
  • > Since we are taking a long-lived reference r to a string slice inner which is destroyed at the end of its scope,
  • `inner` is gone at the end of its scope, yes. However, its *value* still lives on.
  • We have to think about the difference between *values* and *variables*. `r` doesn't reference `inner`, it references `"second"`. What's probably confusing you is that `inner` has a reference as its value, and the lifetime of the *reference* is not the same as the lifetime of the *referenc**ed*** value.
  • ```rust
  • r = inner;
  • ```
  • This performs a copy of the value of `inner`. We are **not** referencing `inner`. Now, what is the value of `inner`? `"second"` is a string literal. It has a lifetime of `static`. Therefore, `inner` has a value of type `&'static str`.
  • After the assignment, the value of `r` thus also a `&'static str`. Indeed, we can actually just specify this and confirm that this compiles cleanly:
  • ```rust
  • let s: &'static str = "first";
  • let mut r: &'static str = s;
  • println!("First ref is {}", r);
  • {
  • let inner: &'static str = "second";
  • r = inner;
  • }
  • println!("Second ref is {}", r);
  • ```
  • If this still confuses you, let's work through a different example:
  • ```rust
  • let s = 1;
  • let mut r = s;
  • println!("First r is {}", r);
  • {
  • let inner = 2;
  • r = inner;
  • }
  • println!("Second r is {}", r);
  • ```
  • This should much more clearly show what's going on. We're just passing around values; who cares that `inner` dies at the end of its scope.
  • -----
  • I said at the beginning that
  • > `r` doesn't reference `inner`, it references `"second"`.
  • What would `r` referencing `inner` look like? Well, we'd borrow it instead of copying its value. (We also have to borrow `s` for parity)
  • ```rust
  • let s: &str = "first";
  • let mut r: &&str = &s;
  • println!("First ref is {}", r);
  • {
  • let inner: &str = "second";
  • r = &inner;
  • }
  • println!("Second ref is {}", r); // !!!!!
  • ```
  • ```
  • |
  • 7 | r = &inner;
  • | ^^^^^^ borrowed value does not live long enough
  • 8 | }
  • | - `inner` dropped here while still borrowed
  • 9 | println!("Second ref is {}", r); // !!!!!
  • | - borrow later used here
  • ```
  • As expected!
  • -----
  • This is getting kind of long, but on a final note, look at how this introduces a double reference. Let's think about lifetimes!
  • ```rust
  • let s: &str = "first"; // &'static str
  • let mut r: &&str = &s; // &'<s> &'static str
  • println!("First ref is {}", r);
  • {
  • let inner: &str = "second"; // &'static str
  • r = &inner; // &'<inner> &'static str
  • }
  • println!("Second ref is {}", r); // !!!!!
  • ```
  • For this purpose, `'<s>` means "has the same lifetime as `s`".
  • This illustrates the point I made earlier: The lifetime of the reference is not the same as the lifetime of the referenc*ed*. At `r = &inner;`, we can see that we have those two lifetimes, the lifetime of `inner` and the lifetime of `"second"`, and those two are not the same.
#1: Initial revision by user avatar Moshi‭ · 2022-07-05T00:55:22Z (over 2 years ago)
## tl;dr, the lifetime of `"second"` is `static`

The heart of your confusion is this:

> Since we are taking a long-lived reference r to a string slice inner which is destroyed at the end of its scope,

`inner` is gone at the end of its scope, yes. However, its *value* still lives on.

We have to think about the difference between *values* and *variables*. `r` doesn't reference `inner`, it references `"second"`. What's probably confusing you is that `inner` has a reference as its value.

```rust
r = inner;
```

This performs a copy of the value `inner`. We are **not** referencing `inner`. `"second"` is a string literal. It has a lifetime of `static`. After the assignment, the value of `r` is a `&'static str`. Indeed, we can actually just specify this and confirm that this compiles cleanly: 

```rust
let s: &'static str = "first";
let mut r: &'static str = s;
println!("First ref is {}", r);
{
    let inner: &'static str = "second";
    r = inner;
}
println!("Second ref is {}", r);
```

If this still confuses you, let's work through a different example: 

```rust
let s = 1;
let mut r = s;
println!("First r is {}", r);
{
    let inner = 2;
    r = inner;
}
println!("Second r is {}", r);
```

This should much more clearly show what's going on. We're just passing around values; who cares that `inner` dies at the end of its scope.

-----

I said at the beginning that

> `r` doesn't reference `inner`, it references `"second"`.

What would `r` referencing `inner` look like? Well, we'd borrow it instead of copying its value. (We also have to borrow `s` for parity)

```rust
let s: &str = "first";
let mut r: &&str = &s;
println!("First ref is {}", r);
{
    let inner: &str = "second";
    r = &inner;
}
println!("Second ref is {}", r); // !!!!!
```

```
  |
7 |     r = &inner;
  |         ^^^^^^ borrowed value does not live long enough
8 | }
  | - `inner` dropped here while still borrowed
9 | println!("Second ref is {}", r); // !!!!!
  |                              - borrow later used here
```

As expected!

-----

This is getting kind of long, but on a final note, look at how this introduces a double reference. Let's think about lifetimes!

```rust
let s: &str = "first"; // &'static str
let mut r: &&str = &s; // &'<s> &'static str
println!("First ref is {}", r);
{
    let inner: &str = "second"; // &'static str
    r = &inner;                 // &'<inner> &'static str
}
println!("Second ref is {}", r); // !!!!!
```

For this purpose, `'<s>` means "has the same lifetime as `s`".