在将它们传递给函数后尝试使用它们时,不可复制的拥有值的生命周期问题

Lifetime issues with non-copyable owned values when trying to use them after passing them to a function

我 运行 遇到了 Rust 中变量生命周期的一些问题。 do_stuff 中的 x 变量借给了 try_wrap,因此在 None 的情况下无法返回。我是不是想错了?

struct NonCopyable;

impl NonCopyable {
    fn new() -> Self {
        NonCopyable
    }
}

fn do_stuff() -> NonCopyable {
    let x = NonCopyable::new();
    match try_wrap(x) {
        Some(val) => val,
        None => x,
    }
}

fn try_wrap(x: NonCopyable) -> Option<NonCopyable> {
    None
}

fn main() {}
error[E0382]: use of moved value: `x`
  --> src/main.rs:13:17
   |
11 |     match try_wrap(x) {
   |                    - value moved here
12 |         Some(val) => val,
13 |         None => x,
   |                 ^ value used here after move
   |
   = note: move occurs because `x` has type `NonCopyable`, which does not implement the `Copy` trait

我认为 Option<NonCopyable> 只是 try_wrap 的错误 return 类型。你需要一个像Result这样的双臂求和类型,这样调用者可以在出错的情况下恢复参数,可能像这样:

fn do_stuff() -> NonCopyable {
    let x = NonCopyable::new();
    match try_wrap(x) {
        Ok(val) => val,
        Err(x) => x,
    }
}

fn try_wrap(x: NonCopyable) -> Result<NonCopyable, NonCopyable> {
    Err(x)
}

with lifetime of variables

这里不涉及生命周期

The x variable in do_stuff is borrowed

不,不是。

Am I thinking about this the wrong way?

是的。借用符号 & and/or 生命周期参数 'foo:

&i32    // a borrowed integer
&'a str // a borrowed string slice with a lifetime
Foo<'b> // a type that contains a borrow of some kind

您的 try_wrap 函数 拥有 x:

fn try_wrap(x: NonCopyable) -> Option<NonCopyable>

这意味着 x 已经消失,调用函数无法再访问它。它已被 移动try_wrap,它现在可以自由地使用该值做任何它想做的事情,包括 销毁它。这就是调用函数不再能够安全访问它以及出现错误的原因。

如果类型实现了 Copy,编译器会隐式创建值的副本并将其传入。如果类型实现了 Clone,您可以显式调用 [=25] =] 在 try_wrap 的参数上,以保持本地值。

notes, you can use a type to return either the wrapped value or the original. It's difficult to tell based on your example, but I disagree with using Result unless it's an error. Instead, I'd create my own one-off enum or use something like Either:

extern crate either;

use either::Either;

fn do_stuff() -> NonCopyable {
    let x = NonCopyable::new();
    match try_wrap(x) {
        Either::Left(val) => val,
        Either::Right(x) => x,
    }
}

fn try_wrap(x: NonCopyable) -> Either<NonCopyable, NonCopyable> {
    Either::Right(x)
}

您还可以将 try_wrap 的逻辑嵌入到 do_stuff 中,或者拆分 try_wrap 这样逻辑就不需要所有权了:

fn do_stuff() -> NonCopyable {
    let x = NonCopyable::new();
    if should_wrap(&x) { do_wrap(x) } else { x }
}

fn should_wrap(x: &NonCopyable) -> bool { false }
fn do_wrap(x: NonCopyable) -> NonCopyable { x }

由于您要返回相同的类型,因此您也可能想要对该值进行可变引用,然后只执行需要发生的任何条件更改:

fn do_stuff() -> NonCopyable {
    let mut x = NonCopyable::new();
    try_wrap(&mut x);
    x
}

fn try_wrap(x: &mut NonCopyable) {}