首页 > 解决方案 > 如何表达闭包的生命周期限制以匹配特征有界生命周期?

问题描述

我有一个特性,它返回一个附加到它自己生命周期的借用:

trait SomeTrait {
    fn do<'a>(&'a self, other: &AnonymousLifetime) -> &'a Output;
}

如何在闭包的where 子句中表达相同的限制,这样SomeTrait可以impl From<Closure>吗?

例子

场景(游乐场)的一个最小的、可重现的示例

// The traits
trait Context {
    fn give(&self) -> usize;
}
trait ContextDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str;
}

// A concrete implementation example
// As expected, works OK
struct SomeDecider(Vec<String>);
impl ContextDecider for SomeDecider {
    fn decide<'a>(&'a self, context: &dyn Context) -> &'a str {
        let some_context = context.give();
        if some_context > self.0.len() {
            panic!("Oh no!");
        }

        &self.0[some_context]
    }
}

// An implemetation for a closure
// Help here!!
impl<'a, F> ContextDecider for F
where
    F: 'a + Fn(&dyn Context) -> &'a str,
{
    fn decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
        self(giver)
    }
}

编译失败:

error[E0312]: lifetime of reference outlives lifetime of borrowed content...
  --> src/lib.rs:30:9
   |
30 |         self(giver)
   |         ^^^^^^^^^^^
   |
note: ...the reference is valid for the lifetime `'b` as defined on the method body at 29:15...
  --> src/lib.rs:29:15
   |
29 |     fn decide<'b>(&'b self, giver: &dyn Context) -> &'b str {
   |               ^^
note: ...but the borrowed content is only valid for the lifetime `'a` as defined on the impl at 25:6
  --> src/lib.rs:25:6
   |
25 | impl<'a, F> ContextDecider for F
   |      ^^

在示例中,我没有在闭包边界中表达特征施加的限制并且编译器不满意。
编译器并没有帮助我使用什么语法来让我将两个生命周期锁定在一起。

标签: rustclosurestraitslifetime

解决方案


你可以应用终身特质绑定ContextDecider吗?(这样你就可以得到 ContextDecider<'a>instead of having the lifetime only on决定`。)

这将导致:

trait Context {
    fn give(&self) -> usize;
}
trait ContextDecider<'a> {
    fn decide(&'a self, context: &dyn Context) -> &'a str;
}

struct SomeDecider(Vec<String>);
impl<'a> ContextDecider<'a> for SomeDecider {
    fn decide(&'a self, context: &dyn Context) -> &'a str {
        let some_context = context.give();
        if some_context > self.0.len() {
            panic!("Oh no!");
        }

        &self.0[some_context]
    }
}

impl<'f, F> ContextDecider<'f> for F
where
    F: 'f,
    for<'ctx>F: Fn(&'ctx dyn Context) -> &'f str,
{
    fn decide(&'f self, giver: &dyn Context) -> &'f str {
        self(giver)
    }
}

推荐阅读