简体   繁体   English

为什么“ impl Trait”返回值实现“ Box时发送” <dyn Trait> `不是吗?

[英]Why does an `impl Trait` return value implement Send while `Box<dyn Trait>` does not?

The solution from How do I store a variable of type `impl Trait` in a struct? 我如何在结构中存储`impl Trait`类型变量的解决方案 suggests creating a Future trait object. 建议创建一个Future trait对象。 Doing that in my real code generates an error that the type is not Send , but the only difference between the working and non working version is the presence or absence of the cast to dyn Future . 在我的真实代码中这样做会产生一个错误,即类型不是Send ,但是工作版本和非工作版本之间的唯一区别是是否存在dyn Futuredyn Future

Why does the compiler see these as different and how do I resolve the problem? 为什么编译器将它们视为不同的,我该如何解决该问题?

Here's a simplified version of the problem: 这是问题的简化版本:

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>>`

From Sending trait objects between threads in Rust , I already know that I can change the trait object to Box<dyn Future<Output = i32> + Send> , but why does this difference exist? 通过在Rust中的线程之间发送特征对象 ,我已经知道可以将特征对象更改为Box<dyn Future<Output = i32> + Send> ,但是为什么存在这种区别?

For ergonomic reasons. 出于人体工程学的原因。 RFC 1522, conservative impl trait , specifically discusses this design decision: RFC 1522,保守的隐含特性 ,专门讨论了此设计决策:

OIBITs leak through an abstract return type. OIBIT通过抽象返回类型泄漏。 This might be considered controversial, since it effectively opens a channel where the result of function-local type inference affects item-level API, but has been deemed worth it for the following reasons: 这可能会引起争议,因为它有效地打开了一个通道,在该通道中,函数局部类型推断的结果会影响项目级API,但由于以下原因,它被认为是值得的:

  • Ergonomics: Trait objects already have the issue of explicitly needing to declare Send / Sync -ability, and not extending this problem to abstract return types is desirable. 人机工程学:特性对象已经存在明确需要声明“ Send / Sync问题,并且不希望将此问题扩展到抽象返回类型。 In practice, most uses of this feature would have to add explicit bounds for OIBITS if they wanted to be maximally usable. 在实践中,如果希望最大程度地使用此功能,则大多数使用都必须为OIBITS添加显式边界。

  • Low real change, since the situation already somewhat exists on structs with private fields: 实际变化不大,因为这种情况在带有私有字段的结构上已经有些存在:

    • In both cases, a change to the private implementation might change whether a OIBIT is implemented or not. 在这两种情况下,对私有实施的更改都可能会更改是否实施OIBIT。
    • In both cases, the existence of OIBIT impls is not visible without documentation tools 在这两种情况下,如果没有文档工具,OIBIT impls的存在是不可见的
    • In both cases, you can only assert the existence of OIBIT impls by adding explicit trait bounds either to the API or to the crate's test suite. 在这两种情况下,您只能通过在API或板条箱的测试套件中添加显式特征范围来断言OIBIT impls的存在。

In fact, a large part of the point of OIBITs in the first place was to cut across abstraction barriers and provide information about a type without the type's author having to explicitly opt in. 实际上,首先,OIBIT的主要目的是跨越抽象障碍并提供有关类型的信息,而类型的作者不必明确选择加入。

This means, however, that it has to be considered a silent breaking change to change a function with an abstract return type in a way that removes OIBIT impls, which might be a problem. 但是,这意味着必须以消除OIBIT impls的方式来更改具有抽象返回类型的函数,才能将其视为沉默的突破性更改,这可能是一个问题。 (As noted above, this is already the case for struct definitions.) (如上所述, struct定义已经是这种情况。)

But since the number of used OIBITs is relatively small, deducing the return type in a function body and reasoning about whether such a breakage will occur has been deemed as a manageable amount of work. 但是,由于使用的OIBIT的数量相对较少,因此在函数体中推断出返回类型并推理是否会发生这种中断已被认为是可管理的工作量。

See also: 也可以看看:

暂无
暂无

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

相关问题 为什么`Box<dyn Sink> ` 在使用 Tokio 和实验性的 async/await 支持时没有实现 `Sink` 特性吗? - Why does `Box<dyn Sink>` not implement the `Sink` trait when using Tokio and the experimental async/await support? 盒子如何<dyn trait>解构自己?</dyn> - How does Box<dyn Trait> deconstruct itself? `Box` 是否掩盖了特征界限? 在这种情况下,为什么我可以将 `dyn FnOnce()` 分配给 `dyn Fn()`? - Does `Box` obscure trait bounds? Why can i assign `dyn FnOnce()` to `dyn Fn()` in this case? 转换选项<impl trait>到一个选项<box<dyn trait> &gt; </box<dyn></impl> - Converting an Option<impl Trait> to an Option<Box<dyn Trait>> 为什么编译器不推断impl特质返回值的关联类型的具体类型? - Why does the compiler not infer the concrete type of an associated type of an impl trait return value? 为什么特征类型为`Box<dyn error> ` 错误“未实现大小”但 `async fn() -&gt; Result&lt;(), Box<dyn error> &gt;` 有效吗?</dyn></dyn> - Why does a trait type `Box<dyn Error>` error with "Sized is not implemented" but `async fn() -> Result<(), Box<dyn Error>>` works? 允许 &amp;[impl Trait] 表现得像 &amp;[&amp;dyn Trait] - Allowing an &[impl Trait] to behave like an &[&dyn Trait] 返回结果<Box<dyn Trait> &gt; 在比赛中 - Return Result<Box<dyn Trait>> in a match 尝试将 Boxed dyn Trait 传递到 Function 时出现“借来的值不够长”的错误 - Getting “borrowed value does not live long enough” Error While Trying to Pass a Boxed dyn Trait into a Function 为什么 Rust 编译器需要 Option&lt;&amp;impl Trait&gt; 的类型注释? - Why does the rust compiler require a type annotation for Option<&impl Trait>?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM