Строка заимствования работает только за пределами блока match

Я новичок в Rust, и в настоящее время у меня проблема с проверкой заимствований. Этот код не компилируется:

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut out = String::new();
        let mut xs = self.xs.iter();
        for x in 0..11 {
            out += match x {
                3 | 7 => "|",
                _ => &xs.next().unwrap().to_string(),
            };
        }
        write!(f, "{}", out)
    }

я получаю ошибку

error[E0716]: temporary value dropped while borrowed
  --> src/main.rs:32:23
   |
30 |               out += match x {
   |  ____________________-
31 | |                 3 | 7 => "|",
32 | |                 _ => &xs.next().unwrap().to_string(),
   | |                       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^-
   | |                       |                            |
   | |                       |                            temporary value is freed at the end of this statement
   | |                       creates a temporary which is freed while still in use
33 | |             };
   | |_____________- borrow later used here
   |
   = note: consider using a `let` binding to create a longer lived value

Однако этот очень похожий код компилируется: (конечно, не с той функциональностью, которую я ищу)

    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut out = String::new();
        let mut xs = self.xs.iter();
        for x in 0..11 {
            out += &xs.next().unwrap().to_string();
        }
        write!(f, "{}", out)
    }

Мой вопрос: почему первый пример не работает, если работает второй? Насколько я понимаю, match следует просто оценивать как то, что оно возвращает, поэтому в случае, когда x не равно 3 или 7, оно должно быть функционально таким же, как во втором примере.

Благодарю вас!

Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
32
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Руки в match могут быть блоками со своими утверждениями. Результатом этого является то, что временные элементы, созданные в руке match, сбрасываются при выходе из руки. Таким образом, временное String, созданное xs.next().unwrap().to_string(), уничтожается до того, как может быть выполнено добавление-назначение, но рука пытается вернуть заимствование против временного, что приводит к висячей ссылке.

Второй пример, который вы показываете, не имеет этой проблемы, потому что он не использует match (или другую блочную конструкцию, такую ​​​​как if), и поэтому временный объект существует до тех пор, пока после не будет выполнено добавление-назначение.

Один из способов обойти это — заставить обе руки match возвращать String:

out += match x {
    3 | 7 => "|".to_string(),
    _     => xs.next().unwrap().to_string(),
};

(Если вам нужно, чтобы match оценивалось как &str, вы можете позаимствовать результат с помощью &match x { ... }, но здесь это не обязательно.)

Конечно, это добавляет дополнительное распределение в случае 3 | 7, но необходимо для согласования типов рук match.

Вместо этого рассмотрите возможность выполнения add-assign внутри match. При таком подходе проблема согласования типов рук уходит, а также решается проблема временного существования:

match x {
    3 | 7 => { out += "|"; }
    _     => { out += xs.next().unwrap().to_string(); }
};

Другие вопросы по теме