为什么编译器不推断impl trait返回值的关联类型的具体类型?

Pie*_*ine 1 type-inference traits rust

我有一个关联类型的特征:

pub trait Speak {
    type Error;
    fn speak(&self) -> Result<String, Self::Error>;
}
Run Code Online (Sandbox Code Playgroud)

该特征的实现:

#[derive(Default)]
pub struct Dog;

impl Speak for Dog {
    type Error = ();
    fn speak(&self) -> Result<String, Self::Error> {
        Ok("woof".to_string())
    }
}
Run Code Online (Sandbox Code Playgroud)

并且函数返回该实现的实例:

pub fn speaker() -> impl Speak {
    Dog::default()
}
Run Code Online (Sandbox Code Playgroud)

我知道在这个例子中我只能Dog用作返回类型,但在我的实际代码中我必须使用impl Speak(上面的函数实际上是由宏生成的).

据我了解,该impl Trait符号让出这实际上返回具体类型编译器的身影,所以我希望下面的函数正确编译,因为speaker()回报Dog,并且Dog::Error是类型():

fn test() -> Result<String, ()> {
    speaker().speak()
}
Run Code Online (Sandbox Code Playgroud)

操场

相反,我收到以下错误:

error[E0308]: mismatched types
  --> src/lib.rs:21:5
   |
20 | fn test() -> Result<String, ()> {
   |              ------------------ expected `std::result::Result<std::string::String, ()>` because of return type
21 |     speaker().speak()
   |     ^^^^^^^^^^^^^^^^^ expected (), found associated type
   |
   = note: expected type `std::result::Result<_, ()>`
              found type `std::result::Result<_, <impl Speak as Speak>::Error>`
Run Code Online (Sandbox Code Playgroud)

就好像编译器不能(在这一点上)推断出speaker函数的返回类型.

谁错过了某些东西,编译器或我自己?

Seb*_*edl 9

使用-> impl Speak<Error = ()>作为返回类型speaker().

问题是编译器只需要签名就需要足够的信息,调用者可以实际使用该函数.如果你只是返回impl Speak,那么编译器知道speak()返回a Result<String, ???>- 错误类型未知,因此编译器发出错误.

编译器无法在此推断任何内容.它无法从呼叫站点推断出错误类型,因为impl Trait返回位置不允许来自呼叫站点的推断.它无法从实现中推断出错误类型,因为这意味着调用者类型检查是否取决于实现,而不是如何impl Trait工作.呼叫者必须始终只在签名信息的情况下进行类型检查; 之后只插入混凝土类型.