为了账号安全,请及时绑定邮箱和手机立即绑定

为什么不能使用impl trait返回多个/条件类型?

为什么不能使用impl trait返回多个/条件类型?

Git
哔哔one 2019-10-23 12:40:03
我正在尝试获得一个随机数生成器。由于OsRng::new()可能会失败,因此我不得不退回给thread_rng()我:extern crate rand; // 0.6.5use rand::{rngs::OsRng, thread_rng, RngCore};fn rng() -> impl RngCore {    match OsRng::new() {        Ok(rng) => rng,        Err(e) => thread_rng(),    }}但是,我收到此错误消息,我无法理解:error[E0308]: match arms have incompatible types --> src/lib.rs:6:5  |6 | /     match OsRng::new() {7 | |         Ok(rng) => rng,8 | |         Err(e) => thread_rng(),  | |                   ------------ match arm with an incompatible type9 | |     }  | |_____^ expected struct `rand::rngs::OsRng`, found struct `rand::prelude::ThreadRng`  |  = note: expected type `rand::rngs::OsRng`             found type `rand::prelude::ThreadRng`为什么编译器期望rand::OsRng在这里而不是实现RngCore?如果删除match并直接返回thread_rng(),则不会得到以上错误消息。我不认为这与如何从方法中返回特征的实例重复吗?,因为另一个问题是关于如何从函数返回特征的问题,而这个问题是关于为什么编译器不允许我返回特征,但希望我返回OsRng不是函数返回类型的。
查看完整描述

2 回答

?
holdtom

TA贡献1805条经验 获得超10个赞

impl Trait不等同于返回接口或基类对象。这是说“我不想写我要返回的特定类型的名称”的一种方式。您仍在返回单个特定类型的值。您只是没有说哪种类型。


这些分支中的每一个都返回不同的类型,因此出现了问题。仅仅实现相同的特征是不够的。


在这种特定情况下,您可能需要的是trait对象Box<dyn RngCore>。


extern crate rand; // 0.6.5


use rand::{rngs::OsRng, thread_rng, RngCore};


fn rng() -> Box<dyn RngCore> {

    match OsRng::new() {

        Ok(rng) => Box::new(rng),

        Err(_) => Box::new(thread_rng()),

    }

}

注意:如果您使用的是Rust的旧版本,则可能需要删除dyn关键字。在当前(2015)版本的Rust中,它是可选的。


查看完整回答
反对 回复 2019-10-23
?
牧羊人nacy

TA贡献1862条经验 获得超7个赞

DK。已经解释了为什么,但是我想提供一个替代的解决方法。


正如提到有条件迭代在几个可能的迭代器一个,您可以创建如果同时它的组件类型做一个实现特征的枚举。例如:


extern crate rand; // 0.6.5


use rand::{rngs::OsRng, thread_rng, RngCore};


fn rng() -> impl RngCore {

    match OsRng::new() {

        Ok(rng) => EitherRng::Left(rng),

        Err(_) => EitherRng::Right(thread_rng()),

    }

}


enum EitherRng<L, R> {

    Left(L),

    Right(R),

}


impl<L, R> RngCore for EitherRng<L, R>

where

    L: RngCore,

    R: RngCore,

{

    fn next_u32(&mut self) -> u32 {

        match self {

            EitherRng::Left(l) => l.next_u32(),

            EitherRng::Right(r) => r.next_u32(),

        }

    }


    fn next_u64(&mut self) -> u64 {

        match self {

            EitherRng::Left(l) => l.next_u64(),

            EitherRng::Right(r) => r.next_u64(),

        }

    }


    fn fill_bytes(&mut self, b: &mut [u8]) {

        match self {

            EitherRng::Left(l) => l.fill_bytes(b),

            EitherRng::Right(r) => r.fill_bytes(b),

        }

    }


    fn try_fill_bytes(&mut self, b: &mut [u8]) -> Result<(), rand::Error> {

        match self {

            EitherRng::Left(l) => l.try_fill_bytes(b),

            EitherRng::Right(r) => r.try_fill_bytes(b),

        }

    }

}

在任一箱提供了很多这些类型的基本特征实现的。


查看完整回答
反对 回复 2019-10-23
  • 2 回答
  • 0 关注
  • 601 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信