以下代码不会编译,因为编译器认为我不应该分配给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);
}
错误是:
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
答案 0 :(得分:6)
您的函数的返回类型是错误的。如果保证返回值没有任何生命周期,那么它应该被标记为这样,并且不会被束缚到任意生命周期:
fn always_returns_no_lifetime(...) -> Types<'static>;
通过此更改,您实际上不再需要任何输入生命周期,因为它们仅用于绑定输入和输出,从而导致以下签名:
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);
}
如果你在不需要的时候保留了生命,你就无法编译这个例子,这是一个不必要的限制。
答案 1 :(得分:3)
不要在引用上应用'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()
}
}