rust - 为什么`impl Trait`返回值在`Box中实现Send`不?
问题描述
How do I store a variable of type `impl Trait` in a struct ? 建议创建一个Future
特征对象。在我的真实代码中这样做会产生一个类型不是的错误Send
,但工作版本和非工作版本之间的唯一区别是是否存在强制转换为dyn Future
.
为什么编译器认为这些不同,我该如何解决这个问题?
这是问题的简化版本:
use std::future::Future;
fn uses_impl_trait() -> impl Future<Output = i32> {
async { 42 }
}
fn uses_trait_object() -> Box<dyn Future<Output = i32>> {
Box::new(async { 42 })
}
fn requires_send<T: Send>(_: T) {}
fn example() {
requires_send(uses_impl_trait()); // Works
requires_send(uses_trait_object()); // Fails
}
error[E0277]: `dyn std::future::Future<Output = i32>` cannot be sent between threads safely
--> src/lib.rs:15:19
|
11 | fn requires_send<T: Send>(_: T) {}
| ------------- ---- required by this bound in `requires_send`
...
15 | requires_send(uses_trait_object());
| ^^^^^^^^^^^^^^^^^^^ `dyn std::future::Future<Output = i32>` cannot be sent between threads safely
|
= help: the trait `std::marker::Send` is not implemented for `dyn std::future::Future<Output = i32>`
= note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<dyn std::future::Future<Output = i32>>`
= note: required because it appears within the type `std::boxed::Box<dyn std::future::Future<Output = i32>>`
从Sending trait objects between threads in Rust,我已经知道我可以将 trait object 更改为Box<dyn Future<Output = i32> + Send>
,但是为什么会存在这种差异呢?
解决方案
出于人体工程学的原因。RFC 1522,conservative impl trait,专门讨论了这个设计决策:
OIBIT 通过抽象返回类型泄漏。这可能会被认为是有争议的,因为它有效地打开了一个通道,其中函数局部类型推断的结果会影响项目级 API,但由于以下原因被认为是值得的:
人机工程学:特征对象已经存在显式需要声明
Send
/能力的问题,Sync
并且不将此问题扩展到抽象返回类型是可取的。在实践中,如果想要最大程度地使用此功能,则必须为 OIBITS 添加明确的界限。实际变化很小,因为这种情况已经存在于具有私有字段的结构上:
- 在这两种情况下,对私有实现的更改可能会改变是否实现了 OIBIT。
- 在这两种情况下,如果没有文档工具,OIBIT impls 的存在是不可见的
- 在这两种情况下,您只能通过向 API 或 crate 的测试套件添加显式特征边界来断言 OIBIT impls 的存在。
事实上,OIBIT 的很大一部分首先是跨越抽象障碍并提供有关类型的信息,而无需类型的作者明确选择加入。
然而,这意味着必须将其视为一种无声的破坏性更改,以通过删除 OIBIT impls 的方式更改具有抽象返回类型的函数,这可能是一个问题。(如上所述,这已经是
struct
定义的情况。)但由于使用的 OIBIT 的数量相对较少,因此在函数体中推导返回类型并推理是否会发生这种损坏已被认为是可管理的工作量。
也可以看看:
推荐阅读
- linker - 是否有人说只为一个配置链接 SPM?
- wpf - 对齐窗口顶部和底部的内容
- r - 使用两个不同的列在行之间变化
- excel - 计算列中不同值的平均价格
- mysql - SQL 错误:尝试插入已设置触发器的表时,“列 [名称] 不能为空”
- android - 布局文件名更改后绑定类未解析
- oracle - 当我们使用 from_options aws 胶水时,hashpartitions 和 no of worker 之间有什么关系?
- bash - grep 数字文件名[10-25]
- c# - 模型对象的 ICollection 始终为空
- css - 当我使用 CSS 将鼠标悬停在按钮上时,如何使按钮中的文本改变颜色?