Traits 返回一个 trait:在某些情况下有效,在其他情况下则无效

and*_*dre 5 rust

我需要实现一个返回futures::StreamExt特征的特征。

一般来说,这听起来很简单,对此有几个答案,例如这里的这个

我试过这个,StreamExt但这确实 - 由于某种原因 - 不起作用。这是我的示例代码:


// [dependencies]
// futures = "0.3.6"
// async-std = { version = "1.6.5", features = ["attributes", "unstable"] } // interval function is unstable atm.
use std::time::Duration;

use futures::StreamExt;

trait StreamProvidingTrait {
  fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
}

struct StreamProvider {}

impl StreamProvidingTrait for StreamProvider {
  fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
    return Box::new(async_std::stream::interval(Duration::from_millis(1000)).map(|_| 1));
  }
}

#[async_std::main]
async fn main() {
  let mut counter = 0;
  let object = StreamProvider {};

  // creates a stream
  let worx = object.returnastream();
  // mappes the stream into something....
  let mut mapped_stream = worx.map(|_| {
    counter = counter + 1;
    counter
  });
  // subscribing to the items
  while let item = mapped_stream.next().await {
    match item {
      Some(value) => println!("{}", value),
      _ => {}
    }
  }
}

Run Code Online (Sandbox Code Playgroud)

这里的错误:

Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
warning: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:1326:8
|
1326 |     fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
|        ^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `poll_next_unpin` references the `Self` type in its `where` clause
|
= note: `#[warn(where_clauses_object_safety)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>

error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:6:36
|
6    |   fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
|                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226  |     fn next(&mut self) -> Next<'_, Self>
|        ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976  |     fn by_ref(&mut self) -> &mut Self {
  |        ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
  ...
      1381 |     fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
  |        ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type

  error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
      --> src/main.rs:12:36
      |
      12   |   fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
        |
    ::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
        |
        226  |     fn next(&mut self) -> Next<'_, Self>
    |        ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
    ...
        976  |     fn by_ref(&mut self) -> &mut Self {
      |        ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
      ...
          1381 |     fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
      |        ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type

      error: aborting due to 2 previous errors; 1 warning emitted

      For more information about this error, try `rustc --explain E0038`.
      error: could not compile `traittest`.

      To learn more, run the command again with --verbose.

          Process finished with exit code 101
Run Code Online (Sandbox Code Playgroud)

当我StreamExt用自己的特性交换特性时,这段代码运行良好。

Compiling traittest v0.1.0 (/Users/andre/repos/traittest)
warning: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:1326:8
|
1326 |     fn poll_next_unpin(&mut self, cx: &mut Context<'_>) -> Poll<Option<Self::Item>>
|        ^^^^^^^^^^^^^^^ the trait cannot be made into an object because method `poll_next_unpin` references the `Self` type in its `where` clause
|
= note: `#[warn(where_clauses_object_safety)]` on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #51443 <https://github.com/rust-lang/rust/issues/51443>

error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
--> src/main.rs:6:36
|
6    |   fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>>;
|                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
|
::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
|
226  |     fn next(&mut self) -> Next<'_, Self>
|        ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
...
976  |     fn by_ref(&mut self) -> &mut Self {
  |        ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
  ...
      1381 |     fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
  |        ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type

  error[E0038]: the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
      --> src/main.rs:12:36
      |
      12   |   fn returnastream(self: &Self) -> Box<dyn StreamExt<Item=i32>> {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `futures_util::stream::stream::StreamExt` cannot be made into an object
        |
    ::: /Users/andre/.cargo/registry/src/github.com-1ecc6299db9ec823/futures-util-0.3.6/src/stream/stream/mod.rs:226:8
        |
        226  |     fn next(&mut self) -> Next<'_, Self>
    |        ---- the trait cannot be made into an object because method `next` references the `Self` type in its return type
    ...
        976  |     fn by_ref(&mut self) -> &mut Self {
      |        ------ the trait cannot be made into an object because method `by_ref` references the `Self` type in its return type
      ...
          1381 |     fn select_next_some(&mut self) -> SelectNextSome<'_, Self>
      |        ---------------- the trait cannot be made into an object because method `select_next_some` references the `Self` type in its return type

      error: aborting due to 2 previous errors; 1 warning emitted

      For more information about this error, try `rustc --explain E0038`.
      error: could not compile `traittest`.

      To learn more, run the command again with --verbose.

          Process finished with exit code 101
Run Code Online (Sandbox Code Playgroud)

这里有什么问题?显然有什么我不明白的地方。请帮助我理解这一点!

use*_*342 6

返回特征的函数可以使用impl Trait语法返回实现特征的不透明类型。返回 trait 的 trait 方法目前不支持此功能,并且需要将 trait 作为 trait 对象返回 - 动态分派的引用或智能指针,例如BoxRc。然而,并非所有 trait 都是对象安全的,坏消息是StreamExt那些不是,因为编译器指出了原因,例如Self在方法返回类型和where子句中引用。

然而,好消息是这不是问题:StreamExt是一个扩展特性,它为所有实现Stream. 所以你不需要费心返回一个dyn StreamExttrait 对象,你可以返回dyn Stream一个,并且你仍然可以StreamExt通过使用use StreamExt. 换句话说,您可以在特征的返回类型中替换Box<dyn StreamExt>with Box<dyn Stream>

您可能会遇到的另一个问题是,Box<dyn Stream>它不适用于需要移动流的方法,其中包括StreamExt. 这些将需要固定流,这可以通过返回Pin<Box<dyn Stream>>而不是Box<dyn Stream>. 甚至有一种boxed()方法StreamExt可以在一次操作中对流进行固定和装箱;使用它的代码看起来像这样(操场):

use futures::stream::{Stream, StreamExt};
use std::pin::Pin;

trait StreamProvidingTrait {
    fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>>;
}

struct StreamProvider {}

impl StreamProvidingTrait for StreamProvider {
    fn returnastream(&self) -> Pin<Box<dyn Stream<Item = i32>>> {
        return tokio::stream::once(0).boxed();
    }
}

fn main() {
    let provider = StreamProvider {};
    let stream = provider.returnastream();
    let _fut = stream.into_future();
}
Run Code Online (Sandbox Code Playgroud)