代码之家  ›  专栏  ›  技术社区  ›  msrd0 Gordon Linoff

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

  •  6
  • msrd0 Gordon Linoff  · 技术社区  · 6 年前

    OsRng::new() 可能会失败,我想回到 thread_rng() 如果我必须:

    extern crate rand; // 0.6.5
    
    use 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 type
    9 | |     }
      | |_____^ 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 线程(R)

    我不相信这是 How do I return an instance of a trait from a method? ,另一个问题是 怎样 为什么? 编译器不允许我返回特征,但希望我返回 OsRng 不是函数的返回类型。

    2 回复  |  直到 5 年前
        1
  •  13
  •   Shepmaster Tim Diekmann    5 年前

    impl 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()),
        }
    }
    

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

        2
  •  10
  •   Shepmaster Tim Diekmann    5 年前

    DK. has already explained why

    如中所述 Conditionally iterate over one of several possible iterators ,则可以创建一个枚举,该枚举实现一个trait(如果其两个组件类型都实现)。例如:

    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),
            }
        }
    }
    

    这个 either crate 为基本特性提供了许多此类实现。