这段奇怪的代码会发出do_the_thing()的错误,表示T的生命周期 不够长:

use std::future::Future;

trait Connection: Send {
    type ExecFut<'a>: Future<Output = ()> + Send
    where
        Self: 'a;

    fn transaction<F>(&mut self, _f: F)
    where
        F: for<'a> FnOnce(&'a mut Self) -> Box<dyn Future<Output = ()> + Send + 'a> + Send,
    {
        unimplemented!()
    }

    fn execute<'a>(&'a mut self) -> Self::ExecFut<'a> {
        unimplemented!()
    }
}

fn do_the_thing<T: Connection>(connection: &mut T) {
    connection.transaction(|conn| {
        Box::new(async move {
            conn.execute().await;
        })
    });
}
error[E0310]: the parameter type `T` may not live long enough
  --> src/main.rs:22:9
   |
22 | /         Box::new(async move {
23 | |             conn.execute().await;
24 | |         })
   | |__________^ ...so that the type `T` will meet its required lifetime bounds
   |
help: consider adding an explicit lifetime bound...
   |
20 | fn do_the_thing<T: Connection + 'static>(connection: &mut T) {
   |                               +++++++++

playground号公路上可以看到.

就我所知,不应隐含要求'static英镑的界限.几乎一切都受到'a的限制,T的任何生命周期 都应该总是超过它的生命周期 .尽管很明显我可能遗漏了一些东西.

我还发现了一些没有帮助的"解决方案":

  1. 按照编译器的建议增加'static是不合理的.它是可以解决的,但我想使用的是真正的Connection,生命周期 不是'static.
  2. 出于某种原因,删除dyn Future上的Send界限会使其通过编译.这对我来说毫无意义.
  3. 如果我使函数是非泛型的,但使用的是Connection而不是'static,它也会编译,这似乎与编译器错误相矛盾.

以上不是真正的代码;最初的动机源于使用diesel-async箱中的AsyncConnection和类似的代码 struct .然而,我希望它代表核心问题,并希望通过了解这里的问题和潜在的解决办法,它们能够得到调整.

推荐答案

通过进一步的修修补补和研究,我发现了这个问题--关于第type ExecFut<'a>条的第where条--GATs: Decide whether to have defaults for where Self: 'a.从这期杂志上的 comments 来看,似乎其他人在强制执行这一限制时也犯了类似的错误.

这个问题提供了一个解决方法,即将您的特征一分为二--一个用于相关类型,另一个用于方法,这样就可以省略where Self: 'a子句:

这违反了我的密码.解决方法?

首先,如果有任何代码违反了添加所需的界限,我们真的需要反馈.其次,解决办法是将GAT转变为超级特征.使用上面的示例,我们的新代码将如下所示:

trait IterableSuper {
    type Item<'x>;
}
trait Iterable: IterableSuper {
    fn iter<'a>(&'a self) -> Self::Item<'a>;
}

在我的示例中这样做可以编译它,但在我的目标用例中它确实开始变得杂乱无章.

我看到的另一个解决办法是引入一个伪函数,该函数使用关联类型,但不与self结合使用.这还允许您省略where Self: 'a子句,因此代码编译:

trait Connection: Send {
    type ExecFut<'a>: Future<Output = ()> + Send;
 // ^^^^^^^^^^^^^^^^ does not need `where Self: 'a`

    fn transaction<F>(&mut self, _f: F)
    where
        F: for<'a> FnOnce(&'a mut Self) -> Box<dyn Future<Output = ()> + Send + 'a> + Send,
    {
        unimplemented!()
    }

    fn execute<'a>(&'a mut self) -> Self::ExecFut<'a> {
        unimplemented!()
    }
    
    fn _disable_lint_for_exec_fut<'a>(_: Self::ExecFut<'a>) { }
 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ dummy function
}

作为附注,还有另一个链接的问题-Problems with GATs, async, and Send-bounds-它描述了类似上面的边界和Send之间的奇怪交互,may解释了为什么删除Send边界会导致代码段编译.还是很奇怪.

Rust相关问答推荐

如何从接收&;self的方法克隆RC

替换可变引用中的字符串会泄漏内存吗?

函数内模块的父作用域的访问类型

是否可以使用Rust宏来构建元组的项?

创建Rust中元对象协议的动态对象 Select /重新分配机制

如何使用RefCell::JOYMOMTborrow 对 struct 不同字段的可变引用

作为1字节位掩码的布尔值 struct

我如何使用AWS SDK for Rust获取我承担的角色的凭据?

在 Rust 中,是否可以定义一个需要实现类型的构造函数的对象安全特征?

使用占位符获取用户输入

Rust Option 的空显式泛型参数

.to_owned()、.clone() 和取消引用 (*) 之间有区别吗?

Rust 如何返回大类型(优化前)?

注释闭包参数强调使用高阶排定特征界限

在1.5n次比较中找到整数向量中的最大和次大整数

如何使用泛型满足 tokio 异步任务中的生命周期界限

如何在 Rust 中将 UTF-8 十六进制值转换为 char?

如何使返回 XMLError 的方法与 anyhow::Error 兼容?

使用 HashMap 条目时如何避免字符串键的短暂克隆?

函数参数的 Rust 功能标志