Невозможно использовать выражение if для добавления в строку вместо оператора if - PullRequest
0 голосов
/ 30 октября 2018

У меня есть следующий код, который отлично работает:

fn main() {
    let mut example = String::new();

    if 1 + 1 == 2 {
        example += &"string".to_string()
    } else {
        example += &'c'.to_string()
    };

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

Когда я изменяю код на это:

fn main() {
    let mut example = String::new();

    example += if 1 + 1 == 2 {
        &"string".to_string()
    } else {
        &'c'.to_string()
    };

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

Я получаю следующую ошибку:

error[E0597]: borrowed value does not live long enough
 --> src/main.rs:5:10
  |
5 |         &"string".to_string()
  |          ^^^^^^^^^^^^^^^^^^^^ temporary value does not live long enough
6 |     } else {
  |     - temporary value dropped here while still borrowed
7 |         &'c'.to_string()
8 |     };
  |     - temporary value needs to live until here

error[E0597]: borrowed value does not live long enough
 --> src/main.rs:7:10
  |
7 |         &'c'.to_string()
  |          ^^^^^^^^^^^^^^^ temporary value does not live long enough
8 |     };
  |     - temporary value dropped here while still borrowed
  |
  = note: values in a scope are dropped in the opposite order they are created

Это не имеет смысла для меня, так как оба фрагмента кажутся идентичными. Почему не работает второй фрагмент?

Ответы [ 2 ]

0 голосов
/ 30 октября 2018

Вы уже видели объяснение, почему этот код не может быть скомпилирован . Вот код, который работает и ближе к вашей цели:

example += &if 1 + 1 == 2 {
    "string".to_string()
} else {
    'c'.to_string()
};

Я бы не стал утверждать, что это идиоматический Rust. Одна вещь, которая бросается мне в глаза - это ненужное распределение "string" в String. Я написал бы этот код, используя String::push_str и String::push:

if 1 + 1 == 2 {
    example.push_str("string");
} else {
    example.push('c');
}

Если бы вы не добавляли строку, я бы просто оценил ее напрямую:

let example = if 1 + 1 == 2 {
    "string".to_string()
} else {
    'c'.to_string()
};

Я мог бы даже использовать динамическую диспетчеризацию (хотя это менее вероятно):

let s: &std::fmt::Display = if 1 + 1 == 2 { &"string" } else { &'c' };
let example = s.to_string();

или

use std::fmt::Write;
let mut example = String::new();
let s: &std::fmt::Display = if 1 + 1 == 2 { &"string" } else { &'c' };
write!(&mut example, "{}", s).unwrap();

Смотри также:

0 голосов
/ 30 октября 2018

Когда вы применяете & к выражениям, Rust автоматически создает анонимные переменные, которым принадлежит результат вычисления выражения. Итак, ваш код примерно эквивалентен

fn main() {
    let mut example = String::new();

    example += if 1 + 1 == 2 {
        let temp1 = "string".to_string();
        &temp1
    } else {
        let temp2 = 'c'.to_string();
        &temp2
    };

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

Как теперь можно ясно увидеть, область действия (и время жизни) temp1 ограничено ветвью true выражения if, а область действия temp2 ограничена false -ветвление if -выражения. Ни область действия / время жизни не выходит за пределы выражения if, поэтому String внутри обеих ветвей if нельзя добавить к example.

В отличие от этого, ваш первый пример примерно эквивалентен

fn main() {
    let mut example = String::new();

    if 1 + 1 == 2 {
        let temp1 = "string".to_string();
        example += &temp1;
    } else {
        let temp2 = 'c'.to_string();
        example += &temp2;
    };

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

и в обоих случаях temp1 и temp2 живут достаточно долго, так что содержимое String s можно скопировать и добавить к example до того, как temp1 и temp2 будут отброшены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...