Проблемы со спецификатором срока службы ржавчины - PullRequest
0 голосов
/ 25 ноября 2018

Рассмотрим следующую программу:

fn func(source: &str, state: & Vec<&str>) {
    println!("{}", source);
    println!("{}", state[0]);
}
fn step<'a>(source: &'a str, state: &mut Vec<&'a str>) {
    state.push(&source[4..10]);
    func(source, state);
    state.push(&source[4..10]);
}
fn main() {
    let source = "abcdefghijklmnopqrstuvwxyz";
    {
        let mut state = Vec::<&str>::new();
        step(source, &mut state);
        step(source, &mut state);
        step(source, &mut state);
    }
}

Компилируется и запускается без ошибок.Я могу полностью понять, почему здесь необходим указатель времени жизни 'a, потому что в противном случае вы можете выполнить:

fn main() {
    let mut state = Vec::<&str>::new();
    {
        let source = "abcdefghijklmnopqrstuvwxyz";
        step(source, &mut state);
        step(source, &mut state);
        step(source, &mut state);
    }
    println!("{}", state[0]);
}

, что приведет к неопределенному выводу.Моя проблема в том, что я хочу упаковать оба аргумента «func» в структуру, но я не могу сделать эту работу:

struct MyStruct<'a, 'b> {
    pub source: &'a str,
    pub state: &'b mut Vec<&'b str>,
}
fn func(arg: MyStruct) {
    println!("{}", arg.source);
    println!("{}", arg.state[0]);
}
fn step<'a>(source: &'a str,
            state: &mut Vec<&'a str>) {
    state.push(&source[4..10]);
    let s = MyStruct{source: source, state: state};
    func(s);
    state.push(&source[4..10]);
}
fn main() {
    let source = "abcdefghijklmnopqrstuvwxyz";
    {
        let mut state = Vec::<&str>::new();
        step(source, &mut state);
        step(source, &mut state);
        step(source, &mut state);
    }
}

Приведенный выше код не компилируется с сообщением об ошибке:

107 |             state: &mut Vec<&'a str>) {
    |             ----- consider changing the type of `state` to `&'a mut std::vec::Vec<&'a str>`
108 |     state.push(&source[4..10]);
109 |     let s = MyStruct{source: source, state: state};
    |                                             ^^^^^ lifetime `'a` required

Если я изменю состояние состояния на & 'mut Vec <&' a str>, сборка завершится неудачно со следующим сообщением:

117 |         step(source, &mut state);
    |                           ----- first mutable borrow occurs here
118 |         step(source, &mut state);
    |                           ^^^^^ second mutable borrow occurs here
119 |         step(source, &mut state);
120 |     }
    |     - first borrow ends here

Я был бы благодарен, если бы кто-нибудь могскажите мне, как заставить это работать.

Примечание. В этом примере программы "source" - это строка со статическим временем жизни.В «реальной» программе «исходный» имеет не статическое время жизни, а содержимое файла, который программа читает во время выполнения.«источник» живет так же долго или дольше, чем «состояние»

1 Ответ

0 голосов
/ 25 ноября 2018

Ситуация времени жизни в параметрах вашей функции такова:

fn step<'a>(source: &'a str,
            state: &mut Vec<&'a str>)

Давайте назовем ссылку, у которой нет явного имени в жизни:

fn step<'a, 'x>(source: &'a str,
                state: &'x mut Vec<&'a str>)

Там, сейчасвсе ссылки имеют явное время жизни, и мы видим, что конфигурация в структуре не соответствует тому, как они соотносятся друг с другом в параметрах функции.

Если ваша структура должна следовать тем же отношениям, мы хотим это:

struct MyStruct<'a: 'x, 'x> {
    pub source: &'a str,
    pub state: &'x mut Vec<&'a str>,
}

И так как это определение типа, нам нужно добавить то отношение, которое было неявным в функции, что 'a: 'x «a outlive» x »

Имейте в виду и васнеобходимо охватить заимствование, которое содержит переменная s типа MyStruct - она ​​заимствует состояние изменчиво (означает исключительно).Поэтому вам нужно вставить области вокруг строки с let s = .. и f(s), чтобы область действия s заканчивалась до вызова следующего шага:

{
    let s = MyStruct{source: source, state: state};
    func(s);
}
...