【问题标题】:How to tell the compiler the variant of the enum I'm returning always has no lifetime?如何告诉编译器我返回的枚举变量总是没有生命周期?
【发布时间】:2018-01-08 05:25:23
【问题描述】:

下面的代码无法编译,因为编译器认为我不应该分配给 t1,因为它是借用的,但实际上函数 always_returns_no_lifetime 将始终返回实际上没有的枚举的变体有一辈子,所以我可以修改t1。我怎样才能让编译器理解这一点,或者我应该如何重新组织我的代码以使这个错误不会发生?

#[derive(Clone)]
enum Types<'a> {
    NoLifetime(i32),
    AlsoNoLifetime(i32),
    AlsoAlsoNoLifetime(i32),
    HasLifetime(&'a str)
}

fn always_returns_no_lifetime<'a>(some_type: &'a Types) -> Types<'a> {
    match *some_type {
        Types::HasLifetime(text) => panic!("I only return the type that has no lifetime"),
        _ => some_type.clone()
    }
}


fn main() {
    let mut t1 = Types::NoLifetime(20);

    let copy = always_returns_no_lifetime(&t1);

    t1 = Types::NoLifetime(30);

}

playground

错误是:

error[E0506]: cannot assign to `t1` because it is borrowed
  --> src/main.rs:23:5
   |
21 |     let copy = always_returns_no_lifetime(&t1);
   |                                            -- borrow of `t1` occurs here
22 |     
23 |     t1 = Types::NoLifetime(30);
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ assignment to borrowed `t1` occurs here

【问题讨论】:

    标签: enums rust borrow-checker


    【解决方案1】:

    您的函数的返回类型错误。如果保证返回值没有任何生命周期,那么它应该被标记为这样,而不是绑定到任意生命周期:

    fn always_returns_no_lifetime(...) -> Types<'static>;
    

    通过此更改,您实际上也不再需要任何 input 生命周期,因为它们仅用于绑定输入和输出,导致以下签名:

    fn always_returns_no_lifetime(some_type: &Types) -> Types<'static>;
    

    不幸的是,这意味着 clone 现在不在表中,因为它克隆了生命周期,所以实现也必须改变:

    fn always_returns_no_lifetime(some_type: &Types) -> Types<'static> {
        match *some_type {
            Types::HasLifetime(_)
                => panic!("I only return values that have no lifetime"),
            Types::NoLifetime(i) => Types::NoLifetime(i),
            Types::AlsoNoLifetime(i) => Types::AlsoNoLifetime(i),
            Types::AlsoAlsoNoLifetime(i) => Types::AlsoAlsoNoLifetime(i),
        }
    }
    

    这个实现的好处可以在下面的例子中得到证明:

    fn tie<'a>(text: &'a str) -> Types<'a> {
        if text[0] == 'a' {
            Types::HasLifetime(text)
        } else {
            Types::NoLifetime(0)
        }
    }
    
    fn main() {
        let no_lifetime = {
            let string = String::from("Hello, world");
            let has_lifetime = tie(&*string);
            always_returns_no_lifetime(&has_lifetime)
        };
    
        //  Requires deriving Debug, all structs really should...
        println!("{:?}", no_lifetime);
    }
    

    如果你在不需要的时候保留生命周期,你不能编译这个例子,这是一个不必要的限制。

    【讨论】:

    • 感谢您的回答,但我不太明白您要在第二个示例中显示什么。我看到你对底部的范围做了什么,但是应该显示什么 tie 函数?
    • @Keatinge:tie 函数正在创建一个 Types&lt;'a&gt;,它将值与其输入的生命周期联系起来(注意它具有相同的生命周期)。这就是导致has_lifetime 与string 变量具有相同生命周期的原因。如果你试图从块中返回has_lifetime,编译器会警告你不能,因为string在块的末尾被销毁。
    【解决方案2】:

    不要在 reference 上应用 'a 生命周期参数,而是在 Types 上应用它,就像您对返回类型所做的那样。当您在其上调用 .clone() 时,引用上的生命周期并不重要。

    fn always_returns_no_lifetime<'a>(some_type: &Types<'a>) -> Types<'a> {
        match *some_type {
            Types::HasLifetime(text) => panic!("I only return the type that has no lifetime"),
            _ => some_type.clone()
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-03-10
      • 1970-01-01
      • 2021-06-30
      • 1970-01-01
      相关资源
      最近更新 更多