【问题标题】:Lifetime of variable in a match pattern匹配模式中变量的生命周期
【发布时间】:2015-01-22 13:14:07
【问题描述】:

尝试编译以下代码:

#[derive(Show)]
pub enum E1 {
    A,
    B,
}
#[derive(Show)]
pub enum E2 {
    X(E1),
    Y(i32),
}

impl std::fmt::String for E1 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Show::fmt(self, f)
    }
}

impl std::fmt::String for E2 {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        std::fmt::Show::fmt(self, f)
    }
}

impl std::error::Error for E2 {
    fn description(&self) -> &'static str {
        match *self {
            E2::X(x) => {
                let d: &'static str = x.description();
                d
            },
            E2::Y(_) => "Unknown error",
        }
    }
}

impl std::error::Error for E1 {
    fn description(&self) -> &'static str {
        match *self {
            E1::A => "Error A",
            E1::B => "Error B",
        }
    }
}

fn main() { }

产生错误:

a.rs:17:39: 17:40 error: `x` does not live long enough
a.rs:17                 let d: &'static str = x.description();
                                              ^
note: reference must be valid for the static lifetime...
a.rs:15:9: 21:10 note: ...but borrowed value is only valid for the match at 15:8
a.rs:15         match *self {
a.rs:16             E2::X(x) => {
a.rs:17                 let d: &'static str = x.description();
a.rs:18                 d
a.rs:19             },
a.rs:20             E2::Y(_) => "Unknown error"
        ...
a.rs:15:15: 15:20 error: cannot move out of borrowed content
a.rs:15         match *self {
                      ^~~~~
a.rs:16:19: 16:20 note: attempting to move value to here
a.rs:16             E2::X(x) => {
                          ^
a.rs:16:19: 16:20 help: to prevent the move, use `ref x` or `ref mut x` to capture value by reference
a.rs:16             E2::X(x) => {
                          ^
error: aborting due to 2 previous errors

将匹配模式更改为 E2::X(ref x) 可能会产生更详细的错误,但让我同样感到困惑:

a.rs:16:19: 16:24 error: cannot infer an appropriate lifetime for pattern due to conflicting requirements
a.rs:16             E2::X(ref x) => {
                          ^~~~~
a.rs:17:39: 17:40 note: first, the lifetime cannot outlive the expression at 17:38...
a.rs:17                 let d: &'static str = x.description();
                                              ^
a.rs:17:39: 17:40 note: ...so that pointer is not dereferenced outside its lifetime
a.rs:17                 let d: &'static str = x.description();
                                              ^
a.rs:15:9: 21:10 note: but, the lifetime must be valid for the match at 15:8...
a.rs:15         match *self {
a.rs:16             E2::X(ref x) => {
a.rs:17                 let d: &'static str = x.description();
a.rs:18                 d
a.rs:19             },
a.rs:20             E2::Y(_) => "Unknown error"
        ...
a.rs:16:19: 16:24 note: ...so that variable is valid at time of its declaration
a.rs:16             E2::X(ref x) => {
                          ^~~~~
error: aborting due to previous error

在我看来,x 只需要生存到x.description() 返回,但编译器似乎需要比整个匹配块生存得更久。为什么?为什么它还坚持将x 视为参考,而复制可能更合乎逻辑?

【问题讨论】:

  • 感谢扩展错误消息!

标签: rust lifetime


【解决方案1】:

对于xref xx 将不起作用,因为您只有对 self 的引用,因此无法将 E1 值移出它——您所能做的就是取一个参考一下。

但现在更重要的是:你对 description 方法的定义不正确,Rust 编译器并没有警告你那个,而是让你的生活变得不愉快.

这是description 方法的实际定义:

fn description(&self) -> &str;

注意:&str,而不是&'static str。编译器应该反对签名中的'static,但可惜它没有。 (这是https://github.com/rust-lang/rust/issues/21508 的主题,由于这个问题而提交。)通常指定更长的生命周期就可以了,因为它只会将其缩小到一定大小,但在某些情况下它不会做你想做的事认为它会 - 具体来说,它已更改 E1description 方法以返回具有自己生命周期的 &str但在 E2 定义中它仍然希望返回 &'static str时间>。当然,x 引用不是'static,所以它做不到。令人困惑,是吗?别担心,这主要不是你的错!

要解决此问题,请删除所有出现的'static,以匹配特征定义。然后因为xself 内部,所以生命周期将适当排列。

【讨论】:

  • 谢谢。但是仍然对一件事感到困惑:x 参考绝对没有足够长的生命周期,但不管x.description() 的输出应该有生命周期'static,不是吗?还是不是因为生命周期的改变,但是编译器没有告诉我这个?
  • @dhardy:你的description 方法不应该处理&'static strs,事实上它为你部分“修复”了它(宽容并允许'static而不是暴力反对) 是什么让你绊倒。
  • 是的,所以编译器在没有告诉我的情况下降级了一生。 :(
  • 感谢您为我省去了麻烦!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-08-21
  • 2015-05-03
  • 1970-01-01
  • 2015-04-22
  • 1970-01-01
  • 2013-07-27
相关资源
最近更新 更多