为什么在返回“ impl Trait”的函数中出现“匹配臂具有不兼容的类型”错误?

时间:2018-07-26 16:03:47

标签: rust

trait Counter {
    fn count(&self) -> i32;
}

struct AddCounter {
    a: i32,
    b: i32,
}
impl Counter for AddCounter {
    fn count(&self) -> i32 {
        self.a + self.b
    }
}

struct MulCounter {
    a: i32,
    b: i32,
}
impl Counter for MulCounter {
    fn count(&self) -> i32 {
        self.a * self.b
    }
}

fn get_counter(a: i32, b: i32, op: &str) -> impl Counter {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

fn main() {}

致电get_counter(...)时出现错误:

error[E0308]: match arms have incompatible types
  --> src/main.rs:26:5
   |
26 | /     match op {
27 | |         "+" => AddCounter { a, b },
28 | |         "*" => MulCounter { a, b },
   | |                ------------------- match arm with an incompatible type
29 | |         _ => panic!(format!("{}{}", "未知的符号:", op)),
30 | |     }
   | |_____^ expected struct `AddCounter`, found struct `MulCounter`
   |
   = note: expected type `AddCounter`
              found type `MulCounter`

1 个答案:

答案 0 :(得分:6)

请参见impl Trait符号作为通用类型。您不能写:

fn get_counter<T>(a: i32, b: i32, op: &str) -> T {
    match op {
        "+" => AddCounter { a, b },
        "*" => MulCounter { a, b },
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

因为AddCounterMulCounter的类型不同:T是什么?

您可以使用动态调度代替静态调度:

fn get_counter(a: i32, b: i32, op: &str) -> Box<dyn Counter> {
    match op {
        "+" => Box::new(AddCounter { a, b }),
        "*" => Box::new(MulCounter { a, b }),
        _ => panic!(format!("{}{}", "未知的符号:", op)),
    }
}

进一步的解释

使用静态分派时,Rust编译器使代码单态化:它为泛型类型的每个值生成一个新函数(有关更多详细信息,请参见What is monomorphisation with context to C++?)。这些返回值中的每一个都是“真实”普通类型。在这种情况下,函数无法在一个路径中返回(例如)String,而在另一路径中返回i32

dynamic dispatch的情况下,返回的不是“真实”类型,而是一个特征对象:编译器不知道真实类型;它只关心trait对象可以用作trait实现者。这就是您的需要。