简体   繁体   English

使用具有显式生命周期的特征时,无法推断借位表达式的生命周期

[英]Unable to infer lifetime for borrow expression when using a trait with an explicit lifetime

use std::io::BufReader;
struct Foo {
    buf: [u8, ..10]
}

trait Bar<'a> {
    fn test(&self, arg: BufReader<'a>) {}
}

impl<'a, T: Bar<'a>> Foo {
    fn bar(&'a mut self, t: T) {
        t.test(BufReader::new(&self.buf));
        let b = &mut self.buf;
    }

    fn baz(&self, t: T) {
        t.test(BufReader::new(&self.buf));
    }
}

fn main() {}

The code above fails to compile, with the error message: 上面的代码无法编译,并显示错误消息:

lifetimes.rs:17:31: 17:40 error: cannot infer an appropriate lifetime for borrow expression due to conflicting requirements
lifetimes.rs:17         t.test(BufReader::new(&self.buf));
                                              ^~~~~~~~~
lifetimes.rs:16:5: 18:6 help: consider using an explicit lifetime parameter as shown: fn baz(&'a self, t: T)
lifetimes.rs:16     fn baz(&self, t: T) {
lifetimes.rs:17         t.test(BufReader::new(&self.buf));
lifetimes.rs:18     }
error: aborting due to previous error

However, if I add the named lifetime parameter, I cannot mutable borrow the buf field after calling test , as seen in fn bar . 但是,如果添加命名的生命周期参数,则无法在调用test之后可变借用buf字段,如fn bar Commenting out the fn baz and trying to compile results in: 注释掉fn baz并尝试将结果编译为:

lifetimes.rs:13:22: 13:30 error: cannot borrow `self.buf` as mutable because it is also borrowed as immutable
lifetimes.rs:13         let b = &mut self.buf;
                                     ^~~~~~~~
lifetimes.rs:12:32: 12:40 note: previous borrow of `self.buf` occurs here; the immutable borrow prevents subsequent moves or mutable borrows of `self.buf` until the borrow ends
lifetimes.rs:12         t.test(BufReader::new(&self.buf));
                                               ^~~~~~~~
lifetimes.rs:14:6: 14:6 note: previous borrow ends here
lifetimes.rs:11     fn bar(&'a mut self, t: T) {
lifetimes.rs:12         t.test(BufReader::new(&self.buf));
lifetimes.rs:13         let b = &mut self.buf;
lifetimes.rs:14     }
                    ^
error: aborting due to previous error

My understanding of this is that by adding the named lifetime 'a to the &'a mut self parameter, the reference taken by BufReader has a lifetime as long as the self reference is valid, which is until the end of the function. 我对此的理解是,通过将命名的生命周期'a添加到&'a mut self参数中, BufReader所采用的引用的生命周期只要该self引用有效即可,直到该函数结束为止。 This conflicts with the mutable borrow of self.buf on the line after. 这与self.buf的可变借用冲突。

However, I am not sure why I need the named lifetime parameter on the self . 但是,我不确定为什么在self上需要命名的生命周期参数。 It seems to me that the BufReader reference should be able to only exist for the lifetime of the t.test method call. 在我看来, BufReader引用应该只能在t.test方法调用的生存t.test存在。 Is the compiler complaining because the self.buf borrow must be ensured to live only as long as the &self borrow? 编译器是否在抱怨,因为必须确保self.buf借用self.buf仅与&self借用self.buf一样长? How would I go about doing that while still only borrowing it for the lifetime of the method call? 我该怎么做,而仍然只在方法调用的整个生命周期内借用它?

Any help in going about fixing this problem and understanding more about the semantics here would be much appreciated! 我们将非常感谢您在解决此问题以及对此处的语义有更多了解方面的任何帮助!

Update 更新资料

So I am still looking into this problem, and I have found this test case and this issue that show basically what I am trying to do. 因此,我仍然在研究这个问题,并且已经找到了这个测试用例这个问题这些问题基本上表明了我正在尝试做的事情。 I would very much like to understand why the error pointed to by the test case link is an error. 我非常想了解为什么测试用例链接所指向的错误是一个错误。

I can see in the issue rustc output that attempts to point out what the error is, but I am having trouble understanding what exactly it is trying to say. 我可以在问题rustc输出中看到试图指出错误的原因,但是我很难理解错误的含义。

Removing all explicit lifetimes also works. 删除所有显式生存期也可以。 I've found that I only add lifetimes when I'm sure I need them (ie to specifiy that two lifetimes should intersect at a given point which can't be known to the compiler). 我发现只有在确定需要时才添加生存期(即,指定在指定点上两个生存期应相交,而编译器无法得知)。

I'm not sure exactly what you're going for, but this compiles (on rustc 0.13.0-nightly (cc19e3380 2014-12-20 20:00:36 +0000)). 我不确定您要干什么,但这会编译(在rustc 0.13.0-nightly(cc19e3380 2014-12-20 20:00:36 +0000)上)。

use std::io::BufReader;
struct Foo {
    buf: [u8, ..10]
}

trait Bar {
    fn test(&self, arg: BufReader) {}
}

impl<T: Bar> Foo {
    fn bar(&mut self, t: T) {
        t.test(BufReader::new(&self.buf));
        let b = &mut self.buf;
    }

    fn baz(&self, t: T) {
        t.test(BufReader::new(&self.buf));
    }
}

Edit 编辑

I'm going to copy-edit my comment here: 我将在此处复制编辑我的评论:

I originally thought that adding a lifetime or generic parameter to the trait / struct / enum was a shorthand for putting it on every method in the trait, but I was wrong . 我本来以为在trait / struct / enum中添加生命周期或通用参数是将其应用于trait中的每个方法的简写,但是我错了 My current understanding is that you add a lifetime to the trait / struct / enum when that item needs to participate in the lifetime, likely because it is storing a reference with that lifetime. 我目前的理解是,当该项目需要参与生命周期时,您可以在trait / struct /枚举中添加生命周期,这可能是因为它存储了具有该生命周期的引用。

struct Keeper<'a> {
    counts: Vec<&'a i32>,
}

impl<'a> Keeper<'a> {
    fn add_one(&mut self, count: &'a i32) {
        if *count > 5 {
            self.counts.push(count);
        }
    }

    fn add_two<'b>(&mut self, count: &'b i32) -> i32 {
        *count + 1
    }
}

fn main() {
    let mut cnt1 = 1;
    let mut cnt2 = 2;
    let mut k = Keeper { counts: Vec::new() };

    k.add_one(&cnt1);
    k.add_two(&cnt2);

    // cnt1 += 1; // Errors: cannot assign to `cnt1` because it is borrowed
    cnt2 += 1; // Just fine

    println!("{}, {}", cnt1, cnt2)
}

Here, we've added a lifetime to Keeper because it might store the reference it is given. 在这里,我们为Keeper添加了生存期,因为它可以存储给定的引用。 The borrow checker must assume that the reference is stored for good when we call add_one , so once we call that method, we can no longer mutate the value. 当我们调用add_one ,借位检查器必须假定引用已存储好,因此,一旦调用该方法,就无法再更改该值。

add_two , on the other hand, creates a fresh lifetime that can only be applied to that function invocation, so the borrow checker knows that once the function returns, it is the One True Owner. 另一方面, add_two创建只能用于该函数调用的新生存期,因此借用检查器知道一旦函数返回,它就是一个真正的所有者。

The upshot is, if you need to store a reference, then there's nothing you can do at this level. 结果是,如果您需要存储参考,那么在此级别您将无能为力。 Rust can't make sure you are safe, and that's something it takes seriously. Rust无法确保您的安全,因此需要认真对待。

However, I bet you don't need to store the reference . 但是,我敢打赌您不需要存储引用 Move the <'a, T: Bar<'a>> from the impl to the fn and you'll be good to go. <'a, T: Bar<'a>>impl移至fn ,您会很方便。

Said another way: I bet you should never have impl<A> if your trait or struct don't require it. 换句话说:我敢打赌,你不应该有impl<A>如果你的特质或结构并不需要它。 Put the generics on the methods instead. 将泛型放在方法上。

Original 原版的

This compiles, but I'm not 100% sure it does what you intended: 可以编译,但是我不是100%确信它能达到您的预期:

impl Foo {
    fn baz<'a, T: Bar<'a>>(&'a self, t: T) {
        t.test(BufReader::new(&self.buf));
    }
}

I fell into this trap myself , so I'll paste what I was told: 我本人也掉进了这个陷阱 ,所以我要粘贴告诉我的内容:

Everything in the impl block is parameterized. impl块中的所有内容均已参数化。 I've actually never seen type parameters added to impl blocks themselves that aren't part of the trait or type definition. 我实际上从未见过将类型参数添加到impl块本身,而这些参数不属于trait或类型定义。 It's far more common to parameterize the individual methods that need it. 参数化需要它的各个方法更为普遍。

Perhaps other comments / answers can help explain in further detail. 也许其他评论/答案可以帮助进一步详细解释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 何时无法推断 Rust 借用检查器的寿命? - When it is not possible to infer the lifetime in the Rust borrow checker? 由于需求冲突,无法推断借用表达式的适当生存期 - Cannot infer an appropriate lifetime for borrow expression due to conflicting requirement(s) 由于需求冲突,无法为借用表达式推断出适当的生命周期 - cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 为具有生命周期的类型实现 Borrow trait - Implementing Borrow trait for a type with a lifetime 尝试在返回迭代器的闭包内改变状态时,Rust 错误“无法推断借用表达式的适当生命周期” - Rust error "cannot infer an appropriate lifetime for borrow expression" when attempting to mutate state inside a closure returning an Iterator Rust - 为借用特征指定生命周期参数 - Rust - Specifying a Lifetime Parameter for the Borrow Trait 在实现Deref特征时无法推断生命周期参数的适当生命周期 - Cannot infer an appropriate lifetime for lifetime parameter while implementing Deref trait 无法推断生命周期参数克隆特征对象的适当生命周期 - Cannot infer an appropriate lifetime for lifetime parameter cloning trait object 由于需求冲突,结构中的访问引用无法推断借用表达式的适当生存期 - access reference in struct causes cannot infer an appropriate lifetime for borrow expression due to conflicting requirements 结构持有的特征对象中的显式生命周期声明 - Explicit lifetime declarations in trait objects held by structs
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM