考虑以下代码:
struct Foo<'a> {
borrowed: &'a u8,
owned_one: Vec<u8>,
owned_two: Vec<u8>,
output: usize
}
impl<'a> Foo<'a> {
fn do_stuff(&mut self) {
self.output = self.owned_one.len();
let zipped = self.owned_one.iter().zip(self.owned_two.iter());
Self::subroutine(&zipped);
}
fn subroutine<Arg: Iterator<Item=(&'a u8, &'a u8)>>(_zipped: &Arg) {}
}
fn main() {
let num = 0u8;
let mut foo = Foo {
borrowed: &num,
owned_one: vec![0],
owned_two: vec![1],
output: 0
};
foo.do_stuff();
let _out = &foo.output;
}
( playground link )
它无法编译,产生以下错误:
error: lifetime may not live long enough
--> src/lib.rs:12:9
|
8 | impl<'a> Foo<'a> {
| -- lifetime `'a` defined here
9 | fn do_stuff(&mut self) {
| - let's call the lifetime of this reference `'1`
...
12 | Self::subroutine(&zipped);
| ^^^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'a`
我不完全理解这个提示 - 当然self
总是将生命周期分配给我们正在impl
绑定(bind)的类? - 但我可以理解 zip()
的两个参数需要持续相同的时间。所以我将 do_stuff
更改为 &'a mut self
。
struct Foo<'a> {
borrowed: &'a u8,
owned_one: Vec<u8>,
owned_two: Vec<u8>,
output: usize
}
impl<'a> Foo<'a> {
fn do_stuff(&'a mut self) {
self.output = self.owned_one.len();
let zipped = self.owned_one.iter().zip(self.owned_two.iter());
Self::subroutine(&zipped);
}
fn subroutine<Arg: Iterator<Item=(&'a u8, &'a u8)>>(_zipped: &Arg) {}
}
fn main() {
let num = 0u8;
let mut foo = Foo {
borrowed: &num,
owned_one: vec![0],
owned_two: vec![1],
output: 0
};
foo.do_stuff();
let _out = &foo.output;
}
但是,现在编译失败:
error[E0502]: cannot borrow `foo.output` as immutable because it is also borrowed as mutable
--> src/lib.rs:27:16
|
26 | foo.do_stuff();
| -------------- mutable borrow occurs here
27 | let _out = &foo.output;
| ^^^^^^^^^^^
| |
| immutable borrow occurs here
| mutable borrow later used here
为什么在 do_stuff
的参数列表中指定 self
的生命周期意味着我突然无法获取对 foo
的不可变引用之后;我能做些什么呢?
最佳答案
写作fn do_stuff(&'a mut self)
在这种情况下,意味着这个借用的 self 的生命周期,必须与这个 self 借用的一样长borrowed
。这通常不是您想要的。
你的错误在这里fn subroutine<Arg: Iterator<Item=(&'a u8, &'a u8)>>(_zipped: &Arg) {}
。想想你的声明的词汇含义。您的方法什么都不返回,但需要“父级”生命周期?没有理由这样做。简单的解决方案就是为您的元素引入新的生命周期。喜欢fn subroutine<'i, Arg: Iterator<Item=(&'i u8, &'i u8)>>(_zipped: &Arg) {}
。除非你的函数返回一些链接到 'a
, parent 的一生不应该在这里。
另外,最好接受 IntoIterator
它更通用,没有理由通过引用来获取它,最后当你有如此复杂的通用时最好使用 where
,真的,如果你想迂腐,你需要两辈子:
fn subroutine<'i, 'j, Arg>(_zipped: Arg)
where
Arg: IntoIterator<Item = (&'i u8, &'j u8)>,
{
}
关于rust - 具有生命周期和后续引用的可变方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/75412434/