借用字符串仅在“匹配”块之外有效

Borrowing string works only outside of `match` block

我是 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 的情况下,它在功能上应该与第二个示例相同。

谢谢!

match中的手臂可以是带有自己语句的块。其影响是在 match 手臂中创建的临时物品在离开手臂时会掉落。因此,由 xs.next().unwrap().to_string() 创建的临时 String 在 add-assign 可以执行之前被销毁,但 arm 正试图 return 借用临时,导致悬空引用。

你展示的第二个例子没有这个问题,因为它没有使用 match(或另一个像 if 这样的块构造)所以临时存在直到 之后执行 add-assign。

解决此问题的一种方法是让 match return 的双臂与 String:

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

(如果您需要 match 作为 &str 求值,您可以使用 &match x { ... } 借用结果,但这里没有必要。)

当然,这在3 | 7的情况下增加了额外的分配,但需要使match武器的类型保持一致。

考虑在 match 中执行 add-assign。通过这种方法,使手臂类型匹配的问题消失了,临时寿命问题也得到了解决:

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