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

Rust 为什么不能使用impl trait返回多个/条件类型?,rust,traits,return-type,Rust,Traits,Return Type,我正试图得到一个随机数发生器。由于OsRng::new()可能会失败,如果必须的话,我想回到thread\u rng(): extern crate rand; // 0.5.5 use rand::{thread_rng, OsRng, RngCore}; fn rng() -> impl RngCore { match OsRng::new() { Ok(rng) => rng, Err(e) => thread_rng()

我正试图得到一个随机数发生器。由于
OsRng::new()
可能会失败,如果必须的话,我想回到
thread\u rng()

extern crate rand; // 0.5.5

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

fn rng() -> impl RngCore
{
    match OsRng::new() {
        Ok(rng) => rng,
        Err(e) => thread_rng()
    }
}
但是,我收到了我无法理解的错误消息:

错误[E0308]:匹配臂的类型不兼容
-->src/lib.rs:6:5
|
6 |/match OsRng::new(){
7 | | Ok(rng)=>rng,
8 | | Err(e)=>thread_rng(),
||------将arm与不兼容的类型匹配
9 | |     }
|| ___;应为结构'rand::OsRng',找到结构'rand::ThreadRng'`
|
=注意:预期类型为`rand::OsRng`
找到类型`rand::ThreadRng`
为什么编译器在这里期望的是
rand::OsRng
,而不是
RngCore
的实现?如果我删除
匹配项
并直接返回
thread\u rng()
,则不会收到上述错误消息


我不认为这是重复的,因为另一个问题是关于如何从函数中返回特征,这个问题是关于为什么编译器不允许我返回一个trait,但希望我返回一个
OsRng
,它不是函数的返回类型。

impl trait
并不等同于返回一个接口或基类对象。这是一种表达“我不想写我返回的特定类型的名称”的方式。您仍然返回单个特定类型的值;你只是没说是哪种类型

每个分支都返回不同的类型,因此出现了问题。实现同样的特性是不够的

在这种特殊情况下,您可能需要一个trait对象,如
Box

extern板条箱兰德;//0.6.5
使用rand::{rngs::OsRng,thread\u rng,RngCore};
fn rng()->Box{
匹配OsRng::new(){
Ok(rng)=>Box::new(rng),
Err()=>Box::new(thread_rng()),
}
}
注意:如果您使用的是稍旧的Rust版本,则可能需要删除
dyn
关键字。在Rust的上一个(2015)版本中,它是可选的。

,但我想提供一个替代解决方案

如中所述,如果特性的两种组件类型都实现,则可以创建实现该特性的枚举。例如:

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),
        }
    }
}
extern板条箱兰德;//0.6.5
使用rand::{rngs::OsRng,thread\u rng,RngCore};
fn rng()->impl RngCore{
匹配OsRng::new(){
正常(rng)=>EitherRng::左(rng),
Err()=>EitherRng::Right(thread_rng()),
}
}
枚举EitherRng{
左(L),
右(R),,
}
为所有RNG安装RNG核心
哪里
L:RngCore,
R:RngCore,
{
fn next_u32(&mut self)->u32{
匹配自我{
EitherRng::Left(l)=>l.next_u32(),
EitherRng::Right(r)=>r.next_u32(),
}
}
fn next_u64(&mut self)->u64{
匹配自我{
EitherRng::Left(l)=>l.next_u64(),
EitherRng::Right(r)=>r.next_u64(),
}
}
fn填充字节(&mut self,b:&mut[u8]){
匹配自我{
EitherRng::Left(l)=>l.fill_字节(b),
EitherRng::Right(r)=>r.fill_字节(b),
}
}
fn try_fill_字节(&mut self,b:&mut[u8])->结果{
匹配自我{
EitherRng::Left(l)=>l.尝试填充字节(b),
EitherRng::Right(r)=>r.尝试填充字节(b),
}
}
}
为基本特性提供了许多此类实现

另见:


dyn关键字在做什么?它在没有任何技术问题的情况下运行良好,这是多余的。引入它是为了“澄清”代码的含义:
dyn RngCore
是一种动态调度的类型,派生自
RngCore
特性<代码>dyn将在未来版本的Rust中被要求。这正是Shepmaster将要编辑的内容,所以我最好现在就结束它。
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),
        }
    }
}