rust - sirve - ¿Por qué no se puede usar el rasgo implícito para devolver tipos múltiples/condicionales?




tipos de datos en c++ definicion (2)

DK. ya ha explicado por qué , pero me gustaría proporcionar una solución alternativa.

Como se menciona en la iteración condicional sobre uno de varios posibles iteradores , puede crear una enumeración que implemente un rasgo si ambos tipos de componentes lo hacen. Por ejemplo:

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

Cualquiera de las dos cajas proporciona muchos de estos tipos de implementaciones para rasgos fundamentales.

Ver también:

  • ¿Cómo devuelvo condicionalmente diferentes tipos de futuros?

Estoy tratando de obtener un generador de números aleatorios. Como OsRng::new() puede fallar, me gustaría volver a thread_rng() si tengo que:

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

Sin embargo, recibo este mensaje de error que no puedo entender:

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`

¿Por qué el compilador espera rand::OsRng aquí en lugar de una implementación de RngCore ? Si thread_rng() la match y devuelvo directamente thread_rng() , no thread_rng() mensaje de error anterior.

No creo que este sea un duplicado de ¿Cómo devuelvo una instancia de un rasgo de un método? , como la otra pregunta es sobre cómo se puede devolver un rasgo de una función, y esta pregunta es sobre por qué el compilador no me permite devolver un rasgo, pero quiere que yo devuelva un OsRng que no sea el tipo de retorno de la función .


impl Trait no es equivalente a devolver una interfaz o un objeto de clase base. Es una forma de decir "No quiero escribir el nombre del tipo específico que estoy devolviendo". Todavía está devolviendo un valor de un tipo único y específico; simplemente no estás diciendo qué tipo.

Cada una de esas ramas está devolviendo diferentes tipos, de ahí el problema. Implementar el mismo rasgo no es suficiente.

Lo que probablemente desee en este caso específico es un objeto de rasgo como 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()),
    }
}

Nota : si está utilizando una versión un poco más antigua de Rust, es posible que deba eliminar la palabra clave dyn . Es opcional en la edición actual (2015) de Rust.





return-type