Lifetimes

30 октомври 2018

Административни неща

Административни неща

Административни неща

Административни неща

Административни неща

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Преговор

Lifetimes

Виждали сме lifetimes

Виждали сме lifetimes

Виждали сме lifetimes

Жизнени цикли

Виждали сме как работи borrow checker-а

1 2 3 4 5 6
{
    let x = 5;
    let r = &x;

    println!("{}", r);
}
5

Жизнени цикли

Виждали сме как работи borrow checker-а

1 2 3 4 5 6 7 8
{
    let r = {
        let x = 5;
        &x
    };

    println!("{}", r);
}
error[E0597]: `x` does not live long enough
  --> /src/main_1.rs:6:10
   |
6  |         &x
   |          ^ borrowed value does not live long enough
7  |     };
   |     - `x` dropped here while still borrowed
...
10 | }
   | - borrowed value needs to live until here

Жизнени цикли

Виждали сме как работи borrow checker-а

1 2 3 4 5 6 7
{
    let x = 5;
    let r1 = &x;
    let r2 = &*r1;

    println!("{}", r2);
}
5

Жизнени цикли

Ами сега?

1 2 3 4 5 6 7 8 9 10
{
    let x = 5;

    let r2 = {
        let r1 = &x;
        &*r1
    };

    println!("{}", r2);
}

Жизнени цикли

Ами сега?

1 2 3 4 5 6 7 8 9 10
{
    let x = 5;

    let r2 = {
        let r1 = &x;
        &*r1
    };

    println!("{}", r2);
}
5

Очевидно работи, но защо?

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- r1
        &*r1            // -+--|--|-- r2
    };                  // -|--+  |
                        //  |     |
    println!("{}", r2); //  |     |
                        // -+     |
}                       // -------+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- r1
        &*r1            // -+--|--|-- r2
    };                  // -|--+  |
                        //  |     |
    println!("{}", r2); //  |     |
                        // -+     |
}                       // -------+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- r1
        &*r1            // -+--|--|-- r2
    };                  // -|--+  |
                        //  |     |
    println!("{}", r2); //  |     |
                        // -+     |
}                       // -------+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- *r1
        &*r1            // -+--|--|-- *r2
    };                  //  |  |  |
                        //  |  |  |
    println!("{}", r2); //  |  |  |
                        //  |  |  |
}                       // -+--+--+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- *r1
        &*r1            // -+--|--|-- *r2
    };                  //  |  |  |
                        //  |  |  |
    println!("{}", r2); //  |  |  |
                        //  |  |  |
}                       // -+--+--+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- *r1
        &*r1            // -+--|--|-- *r2
    };                  //  |  |  |
                        //  |  |  |
    println!("{}", r2); //  |  |  |
                        //  |  |  |
}                       // -+--+--+

Жизнени цикли

Защо работи?

1 2 3 4 5 6 7 8 9 10 11
{
    let x = 5;          // -------+-- x
                        //        |
    let r2 = {          //        |
        let r1 = &x;    // ----+--|-- *r1
        &*r1            // -+--|--|-- *r2
    };                  //  |  |  |
                        //  |  |  |
    println!("{}", r2); //  |  |  |
                        //  |  |  |
}                       // -+--+--+

Жизнени цикли и функции

Какво става ако имаме функция

1 2 3 4 5 6 7
fn longer(x: &str, y: &str) -> &str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}

Жизнени цикли и функции

Какво става ако имаме функция

1 2 3 4 5 6 7
fn longer(x: &str, y: &str) -> &str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}
error[E0106]: missing lifetime specifier
 --> /src/main_6.rs:2:32
  |
2 | fn longer(x: &str, y: &str) -> &str {
  |                                ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Жизнени цикли и функции

Колко трябва да живее стойността, към която сочи result?

1 2 3 4 5 6 7
{
    let s1 = String::from("long string is long");
    {
        let s2 = String::from("short string");
        let result = longer(s1.as_str(), s2.as_str());
    }
}

Lifetime анотации

1 2 3 4 5 6 7
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}

Lifetime анотации

1 2 3 4 5 6 7
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}

Lifetime анотации

1 2 3 4 5 6 7
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}

Lifetime анотации

1 2 3 4 5 6 7
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() {
        x
    } else {
        y
    }
}

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }
1
fn foo<'a>(x: &'a str, y: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }
1
fn foo<'a>(x: &'a str, y: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }
1
fn foo<'a>(x: &'a str, y: &'a str) { }

Lifetime анотации

1
fn foo<'a>(x: &'a str) { }
1
fn foo<'a>(x: &'a str, y: &'a str) { }

Lifetime анотации

1 2 3 4 5 6 7 8 9 10 11 12 13
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() { x } else { y }
}


{
    let s1 = String::from("long string is long");       // ----+-- s1
    {                                                   //     |
        let s2 = String::from("short string");          // --+-|-- s2, 'a
        let result = longer(s1.as_str(), s2.as_str());  //   | |
        println!("The longer string is: {}", result);   //   | |
    }                                                   // --+ |
}                                                       // ----+

Lifetime анотации

1 2 3 4 5 6 7 8 9 10 11 12 13
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() { x } else { y }
}


{
    let s1 = String::from("long string is long");       // ----+-- s1
    let result = {                                      //     |
        let s2 = String::from("short string");          // --+-|-- s2, 'a
        longer(s1.as_str(), s2.as_str())                //   | |
    };                                                  // --+ |
    println!("The longer string is: {}", result);       //     |
}                                                       // ----+
error[E0597]: `s2` does not live long enough
  --> /src/main_12.rs:12:29
   |
12 |         longer(s1.as_str(), s2.as_str())                //   | |
   |                             ^^ borrowed value does not live long enough
13 |     };                                                  // --+ |
   |     - `s2` dropped here while still borrowed
14 |     println!("The longer string is: {}", result);       //     |
15 | }                                                       // ----+
   | - borrowed value needs to live until here

Lifetime анотации

Не е задължително всички lifetime-и да са еднакви

1 2 3
fn first_occurrence<'a, 'b>(s: &'a str, pattern: &'b str) -> Option<&'a str> {
    s.matches(pattern).next()
}

Lifetime elision

Виждали сме и функции, които връщат референция и не използват lifetime анотации

1 2 3 4
fn trim(s: &str) -> &str {
    // ...

}

Защо в някои случаи работи, а в други не?

Lifetime elision

Следните дефиниции са еквивалентни:

1 2 3 4
fn trim(s: &str) -> &str {
    // ...

}

1 2 3 4
fn trim<'a>(s: &'a str) -> &'a str {
    // ...

}

Lifetime elision

Следните дефиниции са еквивалентни:

1 2 3 4
fn trim(s: &str) -> &str {
    // ...

}

1 2 3 4
fn trim<'a>(s: &'a str) -> &'a str {
    // ...

}

Lifetime elision

Следните дефиниции са еквивалентни:

1 2 3 4
fn trim(s: &str) -> &str {
    // ...

}

1 2 3 4
fn trim<'a>(s: &'a str) -> &'a str {
    // ...

}

Lifetime elision

Следните дефиниции са еквивалентни:

1 2 3 4
fn trim(s: &str) -> &str {
    // ...

}

1 2 3 4
fn trim<'a>(s: &'a str) -> &'a str {
    // ...

}

Lifetime elision

Кога трябва да пишем lifetimes?

Lifetime elision

Кога трябва да пишем lifetimes?

Lifetime elision

Кога трябва да пишем lifetimes?

Lifetime elision

Кога трябва да пишем lifetimes?

Lifetime elision

Как работи

За всеки пропуснат lifetime в аргументите се добавя lifetime параметър

1 2 3 4 5
fn print(s: &str);                                  // elided
fn print<'a>(s: &'a str);                           // expanded

fn foo(x: (&u32, &u32), y: usize);                  // elided
fn foo<'a, 'b>(x: (&'a u32, &'b u32), y: usize);    // expanded

Lifetime elision

Как работи

Ако за аргументите има само един lifetime параметър (експлицитен или пропуснат), този lifetime се налага на всички пропуснати lifetimes в резултата

1 2 3 4 5
fn substr(s: &str, until: usize) -> &str;                         // elided
fn substr<'a>(s: &'a str, until: usize) -> &'a str;               // expanded

fn split_at(s: &str, pos: usize) -> (&str, &str);                 // elided
fn split_at<'a>(s: &'a str, pos: usize) -> (&'a str, &'a str);    // expanded

Lifetime elision

Как работи

Ако първият аргумент е &self или &mut self, неговият lifetime се налага на всички пропуснати lifetimes в резултата

1 2 3 4 5
fn get_mut(&mut self) -> &mut T;                                // elided
fn get_mut<'a>(&'a mut self) -> &'a mut T;                      // expanded

fn args(&mut self, args: &[T]) -> &mut Self;                    // elided
fn args<'a, 'b>(&'a mut self, args: &'b [T]) -> &'a mut Self;   // expanded

Lifetime elision

Как работи

Във всички останали случаи е грешка да пропуснем lifetime-а.

1 2 3 4 5 6 7 8 9
fn get_str() -> &str {
    // ...

}

fn longest(x: &str, y: &str) -> &str {
    // ...

}
error[E0106]: missing lifetime specifier
 --> /src/main_16.rs:3:17
  |
3 | fn get_str() -> &str {
  |                 ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but there is no value for it to be borrowed from
  = help: consider giving it a 'static lifetime

error[E0106]: missing lifetime specifier
 --> /src/main_16.rs:8:33
  |
8 | fn longest(x: &str, y: &str) -> &str {
  |                                 ^ expected lifetime parameter
  |
  = help: this function's return type contains a borrowed value, but the signature does not say whether it is borrowed from `x` or `y`

Lifetime coersion

Променливите автоматично минават от по-голям към по-малък lifetime, ако се налага

1 2 3 4 5 6 7 8 9 10 11 12
fn longer<'a>(x: &'a str, y: &'a str) -> &'a str {
    if x.len() >= y.len() { x } else { y }
}


let s1 = "long string is long";         // &'static str

{
    let string = String::from("short"); // --+- 'a
    let s2 = string.as_str();           // --+- &'a str
    let result = longer(s1, s2);        //   |  s1: &'static str -> &'a str
}                                       // --+

Статичен живот

Static Life

Статичен живот

Специалният lifetime 'static.

Оказва че променливата живее за целия живот на програмата.

1
let s: &'static str = "I have a static lifetime.";

Референции в структури

Нека имаме структура, която връща думите от текст.

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Words {
    text: ??,
}

impl Words {
    fn new(text: &str) -> Words {
        unimplemented!()
    }

    fn next_word(&mut self) -> &str {
        unimplemented!()
    }
}

Референции в структури

Нека имаме структура, която връща думите от текст.

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Words {
    text: ??,
}

impl Words {
    fn new(text: &str) -> Words {
        unimplemented!()
    }

    fn next_word(&mut self) -> &str {
        unimplemented!()
    }
}

Референции в структури

Нека имаме структура, която връща думите от текст.

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Words {
    text: ??,
}

impl Words {
    fn new(text: &str) -> Words {
        unimplemented!()
    }

    fn next_word(&mut self) -> &str {
        unimplemented!()
    }
}

Референции в структури

Нека имаме структура, която връща думите от текст.

1 2 3 4 5 6 7 8 9 10 11 12 13
struct Words {
    text: ??,
}

impl Words {
    fn new(text: &str) -> Words {
        unimplemented!()
    }

    fn next_word(&mut self) -> &str {
        unimplemented!()
    }
}

Референции в структури

1 2 3
struct Words {
    text: &str,
}
error[E0106]: missing lifetime specifier
 --> /src/main_19.rs:3:11
  |
3 |     text: &str,
  |           ^ expected lifetime parameter

Референции в структури

1 2 3
struct Words<'a> {
    text: &'a str,
}

Референции в структури

Съответно трябва да добавим lifetime параметъра и към impl блока

1 2 3 4 5 6 7 8 9 10
#[derive(Debug)]
struct Words<'a> {
    text: &'a str,
}

impl<'a> Words<'a> {
    fn new(text: &str) -> Words {
        Words { text }
    }
}

Референции в структури

Животът на структурата е ограничен до това колко живее обектът, от който сме взели референция

1 2 3 4 5 6 7 8 9
let t1 = Words::new("a b c");                // Words<'static>

let t2 = {
    let s = String::from("мой таен низ");   // ---+- 'a
    Words::new(s.as_str())                   //   |- Words<'a>
};                                          // ---+

println!("{:?}", t1);
println!("{:?}", t2);
error[E0597]: `s` does not live long enough
  --> /src/main_22.rs:16:16
   |
16 |     Words::new(s.as_str())                   //   |- Words<'a>
   |                ^ borrowed value does not live long enough
17 | };                                          // ---+
   | - `s` dropped here while still borrowed
...
21 | }
   | - borrowed value needs to live until here

Lifetime elision в impl блок

Как се попълват пропуснатите lifetimes за функцията new?

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Words {
        Words { text }
    }
}

Lifetime elision в impl блок

Expanded:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new<'b>(text: &'b str) -> Words<'b> {
        Words { text }
    }
}

Lifetime elision в impl блок

Expanded:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new<'b>(text: &'b str) -> Words<'b> {
        Words { text }
    }
}

Lifetime elision в impl блок

Expanded:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new<'b>(text: &'b str) -> Words<'b> {
        Words { text }
    }
}

Lifetime elision в impl блок

Ами ако използваме Self?

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Self {
        Words { text }
    }
}

Lifetime elision в impl блок

Ами ако използваме Self?

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Self {
        Words { text }
    }
}
error[E0621]: explicit lifetime required in the type of `text`
 --> /src/main_25.rs:7:9
  |
6 |     fn new(text: &str) -> Self {
  |                  ---- help: add explicit lifetime `'a` to the type of `text`: `&'a str`
7 |         Words { text }
  |         ^^^^^^^^^^^^^^ lifetime `'a` required

Lifetime elision в impl блок

В случая Self означава Words<'a>:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Words<'a> {
        Words { text }
    }
}

Lifetime elision в impl блок

В случая Self означава Words<'a>:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Words<'a> {
        Words { text }
    }
}

Expanded:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new<'b>(text: &'b str) -> Words<'a> {
        Words { text }
    }
}

Lifetime elision в impl блок

В случая Self означава Words<'a>:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &str) -> Words<'a> {
        Words { text }
    }
}

Expanded:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new<'b>(text: &'b str) -> Words<'a> {
        Words { text }
    }
}
error[E0495]: cannot infer an appropriate lifetime for lifetime parameter `'a` due to conflicting requirements
 --> /src/main_26.rs:7:9
  |
7 |         Words { text }
  |         ^^^^^
  |
note: first, the lifetime cannot outlive the lifetime 'b as defined on the method body at 6:12...
 --> /src/main_26.rs:6:12
  |
6 |     fn new<'b>(text: &'b str) -> Words<'a> {
  |            ^^
note: ...so that reference does not outlive borrowed content
 --> /src/main_26.rs:7:17
  |
7 |         Words { text }
  |                 ^^^^
note: but, the lifetime must be valid for the lifetime 'a as defined on the impl at 5:6...
 --> /src/main_26.rs:5:6
  |
5 | impl<'a> Words<'a> {
  |      ^^
  = note: ...so that the expression is assignable:
          expected Words<'a>
             found Words<'_>

Lifetime elision в impl блок

Ако искаме да използваме Self, правилния вариант е:

1 2 3 4 5
impl<'a> Words<'a> {
    fn new(text: &'a str) -> Self {
        Words { text }
    }
}

Имплементация на next_word метода

Live demo

Имплементация на next_word метода

Финален код (с добавени Option-и)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
#[derive(Debug)]
struct Words<'a> {
    text: Option<&'a str>,
}

impl<'a> Words<'a> {
    fn new(text: &'a str) -> Self {
        Words { text: Some(text) }
    }

    fn next_word(&mut self) -> Option<&str> {
        let text = self.text?;
        let mut iter = text.splitn(2, char::is_whitespace);

        match (iter.next(), iter.next()) {
            (Some(word), rest) => {
                self.text = rest;
                Some(word)
            },
            _ => unreachable!()
        }
    }
}

Имплементация на next_word метода

Всичко работи, но дали имаме правилните lifetimes?

1 2 3 4
fn hello() -> &'static str {
    let mut words = Words::new("hello world");
    words.next_word().unwrap()
}
error[E0597]: `words` does not live long enough
  --> /src/main_29.rs:25:5
   |
25 |     words.next_word().unwrap()
   |     ^^^^^ borrowed value does not live long enough
26 | }
   | - borrowed value only lives until here
   |
   = note: borrowed value must be valid for the static lifetime...

warning: variable does not need to be mutable
  --> /src/main_29.rs:24:9
   |
24 |     let mut words = Words::new("hello world");
   |         ----^^^^^
   |         |
   |         help: remove this `mut`
   |
   = note: #[warn(unused_mut)] on by default

Имплементация на next_word метода

Това става, защото резултата от next_word има lifetime колкото self ('b).

1 2 3 4 5 6 7 8 9 10 11 12 13 14
impl<'a> Words<'a> {
    fn next_word<'b>(&'b mut self) -> Option<&'b str> {
        let text = self.text?;
        let mut iter = text.splitn(2, char::is_whitespace);

        match (iter.next(), iter.next()) {
            (Some(word), rest) => {
                self.text = rest;
                Some(word)
            },
            _ => unreachable!()
        }
    }
}

Имплементация на next_word метода

Вместо това може да върнем резултат с lifetime-а на оригиналния низ в полето text ('a).

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
impl<'a> Words<'a> {
    fn next_word(&mut self) -> Option<&'a str> {
        let text = self.text?;
        let mut iter = text.splitn(2, char::is_whitespace);

        match (iter.next(), iter.next()) {
            (Some(word), rest) => {
                self.text = rest;
                Some(word)
            },
            _ => unreachable!()
        }
    }
}

fn hello() -> &'static str {
    let mut words = Words::new("hello world");
    words.next_word().unwrap()
}

fn main() {
    println!("{}", hello());
}
hello

Lifetime bounds

Релацията "надживява"

Lifetime bounds

Релацията "надживява"

Lifetime bounds

Релацията "надживява"

Lifetime bounds

Релацията "надживява"

Lifetime bounds

Релацията "надживява"

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Релацията "надживява" за структури

Lifetime bounds

Quirks

1 2 3
struct Foo<'a, T> {
    r: &'a T,
}
error[E0309]: the parameter type `T` may not live long enough
 --> /src/main_32.rs:3:5
  |
2 | struct Foo<'a, T> {
  |                - help: consider adding an explicit lifetime bound `T: 'a`...
3 |     r: &'a T,
  |     ^^^^^^^^
  |
note: ...so that the reference type `&'a T` does not outlive the data it points at
 --> /src/main_32.rs:3:5
  |
3 |     r: &'a T,
  |     ^^^^^^^^

Lifetime bounds

Quirks

1 2 3
struct Foo<'a, T: 'a> {
    r: &'a T,
}

Дреболийки

Повече референции

1 2 3 4
struct TwoRefs<'a, 'b> {
    text1: &'a str,
    text2: &'b str,
}

Дреболийки

Повече референции

1 2 3 4
struct TwoRefs<'a> {
    text1: &'a str,
    text2: &'a str,
}

Дреболийки

Lifetimes and generics

Aко ни се наложи да декларираме lifetimes и generics заедно, редът на декларация е lifetimes преди generics

1 2 3 4
struct Words<T, 'a> {
    text: &'a str,
    count: T
}
error: lifetime parameters must be declared prior to type parameters
 --> /src/main_36.rs:2:17
  |
2 | struct Words<T, 'a> {
  |                 ^^

Дреболийки

Lifetimes and generics

Aко ни се наложи да декларираме lifetimes и generics заедно, редът на декларация е lifetimes преди generics

1 2 3 4
struct Words<'a, T> {
    text: &'a str,
    count: T
}

Въпроси