1

我不明白为什么v片段的寿命不够长(2),但它在其他情况下有效。如果我不需要clone变量 in (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])
}
4

1 回答 1

4

在第一种情况下,所有权Optionmake_vec调用传递unwrapunwrap 使用Option并返回Vec,其所有权传递给变量v。调用last返回对 的引用v

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

在第三种情况下,所有权Option传递 frommake_vec到调用 to and_thenand_then 消耗,Option并将所有权传递Vec给闭包。闭包中的调用last返回对Vec. 引用的项目被克隆,这会创建一个不同于Vec. 在Vec关闭后删除 时,没有可能导致问题的引用。

您的案例的类型m不同。Option<&u32>如果它们都有效,则第一种和第二种情况将返回 a 。第三种情况返回 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());

这里的克隆实际上是在内存中复制东西,还是编译器会对其进行优化以有效地将向量元素的所有权传回?由于自始至终都是 u32s,我希望它们通常会被复制而不是引用。

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

于 2015-12-30T20:34:54.530 回答