Как предоставить дополнительную информацию о типе векторному процессору generi c - PullRequest
0 голосов
/ 04 февраля 2020

getter вызывает черты для извлечения универсального c векторного типа:

fn getter<T>(sin: &str) -> Result<Vec<T>, Error> where T: GenVecStruct

Я ожидаю, что компилятору не будет важен закомментированный код (строка 37) в обработчике ниже, так как отлично работает со строками 42, 43 и 44 **.

 33 fn process<F>(input: &InType, mut callback: F) where F: FnMut(OutType), {
 34     if let Ok(data) = getter("two B") {
 35         match input {
 36             InType::SomeInA => for v in data { callback(OutType::OutA(v)); }
 37             // InType::SomeInB => for v in data { callback(OutType::OutB(v)); },
 38             _ => (),
 39         };
 40     }
 41
 42     callback(OutType::OutA(A{a:1}));    //No problem here
 43     callback(OutType::OutB(B{b:1.}));   //No problem here
 44     callback(OutType::Note);            //No problem here either
 45 }

Компиляция с L37 выдает следующую ошибку:

error[E0308]: mismatched types  
--> src/main.rs:37:71  
   | 
37 |             InType::SomeInB => for v in data { callback(OutType::OutB(v)); },
   |                                                                       ^ expected struct `B`, found struct `A`

Вопросы:

  1. Точные рассуждения: если getter производит обобщенный c Vec<T>, следующее соответствие требует дополнительной информации о типе.
  2. Как использовать дженерики, как лучше добавить дополнительную информацию о типе в processor? (макросы - в худшем случае)

Полный пример :

pub enum Error {E1,}

pub trait GenVecStruct where Self: Sized, 
{
    fn to_vec_of_t(s: &str) -> Result<Vec<Self>, Error>;
}

enum InType { SomeInA, SomeInB, }
enum OutType { OutA(A), OutB(B), OutE(Error), Note,}
struct A { a: i32, }
struct B { b: f64, }

impl GenVecStruct for A {
    fn to_vec_of_t(_s: &str) -> Result<Vec<A>, Error> {
        Ok(vec![A { a: 1 }, A { a: 2 }, A { a: 3 }])
    }
}

impl GenVecStruct for B {
    fn to_vec_of_t(_s: &str) -> Result<Vec<B>, Error> {
        Ok(vec![B { b: 9. }, B { b: 8. }, B { b: 6. }])
    }
}

fn getter<T>(sin: &str) -> Result<Vec<T>, Error> where T: GenVecStruct,
{
    match T::to_vec_of_t(sin) {
        Ok(r) => Ok(r),
        Err(_) => Err(Error::E1),
    }
}

fn process<F>(input: &InType, mut callback: F) where F: FnMut(OutType),
{
    if let Ok(data) = getter("two B") {
        match input {
            InType::SomeInA => {
                for v in data {
                    callback(OutType::OutA(v));
                }
            }
fn process<F>(input: &InType, mut callback: F) where F: FnMut(OutType),
{
    if let Ok(data) = getter("two B") {
        match input {
            InType::SomeInA => for v in data{ callback(OutType::OutA(v)); },
         // InType::SomeInB => for v in data{ callback(OutType::OutB(v)); },
            _ => (),
        };
    };

    callback(OutType::OutA(A { a: 1 })); //No problem here
    callback(OutType::OutB(B { b: 1. })); //No problem here
    callback(OutType::Note); //No problem here either
}

fn main() {
    let v = InType::SomeInB;
    process(&v, |p| {
        match p {
            OutType::OutA(_) => println!("someIn A"),
            OutType::OutB(_) => println!("someIn B"),
            OutType::OutE(_) => println!("err"),
            OutType::Note => println!("Note"),
        };
    });
}

1 Ответ

1 голос
/ 04 февраля 2020

Ваш пример далек от минимального воспроизводимого примера . Следуя указаниям Rust c MRE , вы можете значительно сократить свой исходный код:

trait T {}

struct A;
impl T for A {}

struct B;
impl T for B {}

fn use_a(_: A) {}
fn use_b(_: B) {}

fn getter<T>() -> T {
    unimplemented!()
}

fn process() {
    let data = getter();

    if true {
        use_a(data);
    } else {
        use_b(data);
    }
}
error[E0308]: mismatched types
  --> src/lib.rs:21:15
   |
21 |         use_b(data);
   |               ^^^^ expected struct `B`, found struct `A`

В частности, если вы поменяете местами порядок вызовов методов, вы ' Появится связанная, но другая ошибка:

fn process() {
    let data = getter();

    if true {
        use_b(data);
    } else {
        use_a(data);
    }
}
error[E0308]: mismatched types
  --> src/lib.rs:22:15
   |
22 |         use_a(data);
   |               ^^^^ expected struct `A`, found struct `B`

Rust - это статически типизированный язык , что означает, что каждая переменная должна иметь один известный тип при компиляции кода. Это невозможно с вашим кодом; вы хотите, чтобы data был или тип A или B в зависимости от того, что будет делать какое-то будущее условие. Для компилятора нет никакой разницы между тем, что вы написали, и этим более явно некорректным кодом:

fn process() {
    let data = getter();

    use_a(data);
    use_b(data);
}

Вывод типа показал, что для одного вызова требуется, чтобы data был типа A, так что быть типом, который был выбран. Затем этот тип завершается ошибкой, когда ожидается, что он будет B.

Вместо этого вызовите функцию getter внутри каждого условного плеча, создав две отдельные переменные:

fn process() {
    if true {
        let data = getter();
        use_a(data);
    } else {
        let data = getter();
        use_b(data);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...