匹配模式中变量的生命周期
Lifetime of variable in a match pattern
正在尝试编译以下代码:
#[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()
returns,但编译器似乎认为它需要比整个匹配块存活得更久。为什么?为什么它还坚持将 x
作为参考,而复制可能更合乎逻辑?
至于 x
与 ref x
,x
将不起作用,因为您只有对 self
的引用,因此无法移动 E1
它的价值——你所能做的就是引用它。
但现在更重要的是:你对 description
方法的定义不正确,Rust 编译器不会警告你 that 但是反而让你的生活变得不愉快。
这是description
方法的实际定义:
fn description(&self) -> &str;
注意:&str
,不是&'static str
。编译器应该反对签名中的 'static
,但是,唉,它没有。 (这是 https://github.com/rust-lang/rust/issues/21508 的主题,因为这个问题而提交。)通常指定更长的生命周期就可以了,因为它只会缩小它的大小,但在某些情况下它不会做正如您所想的那样——具体来说,它已将 E1
的 description
方法更改为 return 具有自己生命周期的 &str
, 但在 E2
定义它还是要return&'static str
。当然,x
引用的不是'static
,所以做不到。令人困惑,是吧?别担心,这多半不是你的错!
要解决此问题,请删除所有出现的 'static
,以匹配特征定义。然后因为 x
在 self
内,生命周期将适当地排列。
正在尝试编译以下代码:
#[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()
returns,但编译器似乎认为它需要比整个匹配块存活得更久。为什么?为什么它还坚持将 x
作为参考,而复制可能更合乎逻辑?
至于 x
与 ref x
,x
将不起作用,因为您只有对 self
的引用,因此无法移动 E1
它的价值——你所能做的就是引用它。
但现在更重要的是:你对 description
方法的定义不正确,Rust 编译器不会警告你 that 但是反而让你的生活变得不愉快。
这是description
方法的实际定义:
fn description(&self) -> &str;
注意:&str
,不是&'static str
。编译器应该反对签名中的 'static
,但是,唉,它没有。 (这是 https://github.com/rust-lang/rust/issues/21508 的主题,因为这个问题而提交。)通常指定更长的生命周期就可以了,因为它只会缩小它的大小,但在某些情况下它不会做正如您所想的那样——具体来说,它已将 E1
的 description
方法更改为 return 具有自己生命周期的 &str
, 但在 E2
定义它还是要return&'static str
。当然,x
引用的不是'static
,所以做不到。令人困惑,是吧?别担心,这多半不是你的错!
要解决此问题,请删除所有出现的 'static
,以匹配特征定义。然后因为 x
在 self
内,生命周期将适当地排列。