特征返回特征:在某些情况下有效,在其他情况下无效

2023-12-29

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

一般来说,这听起来很简单,并且有几个答案,例如这里 https://stackoverflow.com/questions/60143046/how-can-a-rust-trait-object-return-another-trait-object.

我尝试过这个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),
      _ => {}
    }
  }
}

这里是错误:

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

当我交换StreamExt与我自己的特征相比,这段代码运行得很好。


trait SomeTrait {
  fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait>;
}

trait SomeOtherTrait {
  fn sayHelloWorld(&self);
}

struct DummyStruct {}

impl SomeOtherTrait for DummyStruct {
  fn sayHelloWorld(&self) {
    println!("hello world");
  }
}

struct Implementation {}

impl SomeTrait for Implementation {
  fn returnatrait(self: &Self) -> Box<dyn SomeOtherTrait> {
    return Box::new(DummyStruct{});
  }
}

fn main() {
  let implementation = Implementation{};

  let worx = implementation.returnatrait();

  worx.sayHelloWorld();
}

这是怎么回事?显然有一些我不明白的事情。请帮助我理解这一点!


返回特征的函数可以使用impl Trait返回实现该特征的不透明类型的语法。当前返回特征的特征方法不支持 https://rust-lang.github.io/rfcs/2071-impl-trait-existential-types.html#motivation此功能并要求将特征作为特征对象返回 - 动态分派的引用或智能指针,例如Box or Rc。并不是所有的特质都是对象安全 https://doc.rust-lang.org/book/ch17-02-trait-objects.html#object-safety-is-required-for-trait-objects不过,坏消息是StreamExt由于编译器指出的原因,例如引用,属于那些不属于Self在方法返回类型和where条款。

然而,好消息是这不是问题:StreamExt是一种扩展特征,它为所有实现Stream。所以你不需要费心退货dyn StreamExt特征对象,你可以返回一个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();
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

特征返回特征:在某些情况下有效,在其他情况下无效 的相关文章

随机推荐

  • 使用 Json.NET 读取大整数

    我有一些带有巨大整数的 json 大约有几百位数字 我想将它们解析为 BouncyCastle 的BigInteger https github com onovotny BouncyCastle PCL blob pcl crypto s
  • 如何在 Mac Os X 上将用户添加到 apache 组?

    我实际上正在尝试在我的 MacBook Pro Mac OS X 10 6 上运行 Symfony2 当我通过 apache 启动应用程序时 所有缓存和日志文件都是由 www www 用户 组创建的 但是 我已经必须使用我自己的用户在 CL
  • 使用 rvest 跟随带有相对路径的“下一个”链接

    我正在使用rvest从页面中抓取信息的包http www radiolab org series podcasts http www radiolab org series podcasts 抓取第一页后 我想点击底部的 下一步 链接 抓取
  • 可以将PreparedStatement.addBatch()用于SELECT查询吗?

    想象一下 我有 100 个 SELECT 查询 它们因一个输入而异 可以使用PreparedStatement 作为该值 我在网上看到的所有文档都是关于批量插入 更新 删除的 我从未见过用于 select 语句的批处理 这可以做到吗 如果是
  • 有哪些好的实体框架替代品[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我现在正在使用实体框架 并且经常需要编写内联sql 因为实体框架不支持全文搜索和其他功能 是否有一个 ORM 具有许多支持高级查询的功能
  • Wix 和 .NET Framework(先决条件)

    当客户端计算机上尚未安装所需的 NET Framework 时 如何让 Wix 包下载该包 我已经有条件检查已安装的 NET 版本 但我不确定如何在找不到时下载并安装它 ClickOnce 通过检查属性页中的先决条件自动执行此操作 由于一些
  • android-viewflipper 的简单淡出和淡入动画

    我是android新手 对android动画了解不多 我有一个取景器 我想在其中的图像之间制作动画 这是代码 runnable new Runnable public void run handler postDelayed runnabl
  • Oracle,向字符串(不是数字)添加前导零

    我正在使用 Oracle 工作空间是 TOAD 我需要将字符串设置为短接 10 个字符 然后添加前导零以使它们全部为 10 位数字字符串 例如 如果我有一个像这样的字符串 12H89 需要是 0000012H89 或者 1234 变为 00
  • C++中**是什么意思? [复制]

    这个问题在这里已经有答案了 例如 bool insertInFront IntElement head int data IntElement newElem new IntElement if newElem return false n
  • Google 通讯录 api (gdata) 同步低分辨率照片

    我正在使用 google 联系人 api gdata 在 google 联系人中设置联系人的照片 我正在使用 fiddler 我看到请求是根据Google 通讯录示例 https developers google com google a
  • Angular Spectator setInput 不适用于非字符串输入

    我已经成功地将我的项目转换为使用 Jest 代替 Karma Jasmine 并且我有很多测试运行得很好 我正在尝试使用 Spectator 5 2 1 进行一个非常简单的测试 但它不起作用 我正在尝试测试使用 mat table 呈现表格
  • Rails 路由的 API 版本控制

    我正在尝试像 Stripe 那样对我的 API 进行版本控制 下面给出的最新 API 版本是 2 api users返回 301 api v2 users api v1 users返回版本 1 的 200 个用户索引 api v3 user
  • 多条件IF语句

    我有一个包含多个条件的 if 语句 但我似乎无法正确执行 if ISSET SESSION status SESSION username qqqqq ISSET SESSION status SESSION company wwwwww
  • Kotlin 中通过反射获取 Enum 值

    您将如何用 Kotlin 重写以下 Java 代码 SuppressWarnings unchecked rawtypes static Object getEnumValue String enumClassName String enu
  • 如何将顶视图折叠成较小尺寸的视图?

    这个问题之前曾以过于宽泛和不清楚的方式提出过here https stackoverflow com q 47053822 878126 所以我使它更加具体 并提供了我所尝试的完整解释和代码 背景 我需要模仿谷歌日历在顶部有一个视图的方式
  • JavaScript 中的构造函数或对象继承

    我是 JavaScript 新手 本周开始学习 我已经完成了 CodeCademy 课程 实际上只是对象 1 2 部分 其余的很无聊 我以为我学会了构造函数的原型继承 但我已经开始观看了Douglas Crockford 高级 JavaSc
  • 在两个curl请求之间保存cookie

    我知道使用cURL我可以使用以下命令查看收到的 cookie 标头 curl head www google com 我知道我可以使用以下方法将标头添加到我的请求中 curl cookie Key Value www google com
  • Android 以编程方式重置出厂设置

    我尝试使用 RecoverySystem 类在 Android 中执行恢复出厂设置 但出现权限错误 但我无法覆盖这些错误 因为它们是系统权限 我想知道是否还有其他方法可以恢复出厂设置 第三方应用程序绝对可以做到这一点 在 2 2 设备 包括
  • 将 LUIS 对话框连接到表单对话框并映射正确的字段

    我正在开发一个可以预订航班的机器人 我正在使用最新版本的机器人框架 1 1 如建议 https stackoverflow com questions 36712912 mapping luis entities to dialog fie
  • 特征返回特征:在某些情况下有效,在其他情况下无效

    我需要实现一个返回的特征futures StreamExt trait 一般来说 这听起来很简单 并且有几个答案 例如这里 https stackoverflow com questions 60143046 how can a rust