在我克隆它之前,Vector 的寿命不够长

Vector doesn't live long enough until I clone it

我不明白为什么 v 在代码段 (2) 中的寿命不够长,但它在其他情况下有效。如果我不需要 clone (1) 中的变量,为什么我需要克隆它才能使第二种情况起作用?

fn main() {
    // (1)
    let v = make_vec().unwrap();
    let m = v.last();

    // (2) v doesn't live long enough!
    let m = make_vec()
        .and_then(|v| v.last());

    // (3) Fixed!
    let m = make_vec()
        .and_then(|v| v.last().cloned());
}

fn make_vec() -> Option<Vec<u32>> {
    Some(vec![1, 2, 3])
}

在第一种情况下,Option 的所有权从 make_vec 转移到 unwrap 调用。 unwrap 消耗 选项和 returns Vec,其所有权传递给变量 v。对 last return 的调用是对 v.

的引用

在第二种情况下,Option 的所有权从 make_vec 转移到对 and_then 的调用。 and_then 消耗 Option,并将 Vec 的所有权传递给闭包。在闭包 return 中对 last 的调用是对 Vec 的引用。由于闭包拥有向量但现在已完成 运行,因此 Vec 将被删除。对 Vec 的引用将指向不再有效的内存,因此会出现编译错误。

在第三种情况下,Option 的所有权从 make_vec 转移到对 and_then 的调用。 and_then 消耗 Option,并将 Vec 的所有权传递给闭包。在闭包 return 中对 last 的调用是对 Vec 的引用。 referred-to 项目被克隆,创建一个不同于 Vec 的新项目。当 Vec 在关闭后被删除时,没有对它的引用可能会导致问题。

m 的类型因您的案例而异。如果第一种和第二种情况都有效,它们将是 return 和 Option<&u32>。第三种情况 returns a Option<u32>.

还有第四个选项:

let r = make_vec();
let m = r.as_ref().and_then(|v| v.last());

这会将 Option<T> 转换为 Option<&T>。这个新的 Option 引用 原始 选项,可以通过调用 and_then.

使用

还有第五种选择! ^_^ 如果你只是打算扔掉这个向量,你可以更明确地说明你无论如何都要拿走它的事实:

let m = make_vec().and_then(|v| v.pop());

Does clone here actually copy things in memory or will the compiler optimise it to effectively pass the ownership of the vector element back? Since this was u32s throughout, I was expecting that they would generally be copied instead of referenced.

优化是一件棘手的事情,唯一正确的答案是查看优化后的输出。 I 会假设任何 Copy 和 "small enough" 都不会真正引起问题。但是,我可能会考虑让我的代码尽可能语义化,以帮助优化器。如果该代码是您的意思,我可能会尝试使用 pop 变体。