More on lifetimes

pull/1/head
Dhghomon 4 years ago committed by GitHub
parent 9bfa3a92e1
commit ccfe1e578f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -3860,6 +3860,162 @@ So now ```fn returns_str() -> &'static str``` tells Rust: "don't worry, we will
But ```'static``` is not the only lifetime. Actually, every variable has a lifetime, but usually we don't have to write it. We only have to write the lifetime when the compiler doesn't know.
Here is an example of another lifetime. Imagine we want to create a ```City``` struct and give it a ```&str``` for the name. Later we will have many more ```&str```s because we need faster performance than with ```String```. So we write it like this, but it won't work:
```rust
#[derive(Debug)]
struct City {
name: &str,
date_founded: u32,
}
fn main() {
let my_city = City {
name: "Ichinomiya",
date_founded: 1921,
};
}
```
The compiler says:
```
error[E0106]: missing lifetime specifier
--> src\main.rs:3:11
|
3 | name: &str,
| ^ expected named lifetime parameter
|
help: consider introducing a named lifetime parameter
|
2 | struct City<'a> {
3 | name: &'a str,
|
```
Rust needs a lifetime for ```&str``` because ```&str``` is a reference. What happens when the value that ```name``` points to is dropped? That would be unsafe.
What about ```'static```, will that work? We used it before. Let's try:
```rust
#[derive(Debug)]
struct City {
name: &'static str, // change &str to &'static str
date_founded: u32,
}
fn main() {
let my_city = City {
name: "Ichinomiya",
date_founded: 1921,
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
Okay, that works. And maybe this is what you wanted for the struct. However, note that we can only take "string literals", so not references to something else. So this will not work:
```rust
#[derive(Debug)]
struct City {
name: &'static str, // must live for the whole program
date_founded: u32,
}
fn main() {
let city_names = vec!["Ichinomiya".to_string(), "Kurume".to_string()]; // city_names does not live for the whole program
let my_city = City {
name: &city_names[0], // This is a &str, but not a &'static str. It is a reference to a value inside city_names
date_founded: 1921,
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
The compiler says:
```
error[E0597]: `city_names` does not live long enough
--> src\main.rs:12:16
|
12 | name: &city_names[0],
| ^^^^^^^^^^
| |
| borrowed value does not live long enough
| requires that `city_names` is borrowed for `'static`
...
18 | }
| - `city_names` dropped here while still borrowed
```
So now we will try what the compiler suggested before. It said to try writing ```struct City<'a>``` and ```name: &'a str```. This means that it will only take a reference for ```name``` if it lives as long as ```City```.
```rust
#[derive(Debug)]
struct City<'a> { // City has lifetime 'a
name: &'a str, // and name also has lifetime 'a.
date_founded: u32,
}
fn main() {
let city_names = vec!["Ichinomiya".to_string(), "Kurume".to_string()];
let my_city = City {
name: &city_names[0],
date_founded: 1921,
};
println!("{} was founded in {}", my_city.name, my_city.date_founded);
}
```
Also remember that you can write anything instead of ```'a``` if you want:
```rust
#[derive(Debug)]
struct City<'city> { // The lifetime is now called 'city
name: &'city str, // and name has the 'city lifetime
date_founded: u32,
}
```
So usually you will write ```'a, 'b, 'c``` etc. because it is quick and the usual way to write. But you can always change it if you want.
Also remember this important fact: ```'a``` etc. don't change the actual lifetime of variables. They are like traits for generics. Remember when we wrote generics? For example:
```rust
fn prints<T: Display>(input: T) {
println!("T is {}", input);
}
```
When you write ```T: Display```, it means "please only take T if it has Display".
It does not mean: "I am giving Display to T".
The same is true for lifetimes. When you write 'a here:
```rust
#[derive(Debug)]
struct City<'a> {
name: &'a str,
date_founded: u32,
}
```
It means "please only take an input for ```name``` if it lives at least as long as ```City```".
It does not mean: "I will make the input for ```name``` live as long as ```City```".
# Interior mutability
## Cell

Loading…
Cancel
Save