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

标签 rust traits type-inference

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

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

该特征的实现:

#[derive(Default)]
pub struct Dog;

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

以及返回该实现实例的函数:

pub fn speaker() -> impl Speak {
    Dog::default()
}

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

据我了解,impl Trait 表示法让编译器找出实际返回的具体类型,因此我希望以下函数能够正确编译,因为 speaker() 返回一个 Dog 并且 Dog::Error 是类型 ():

fn test() -> Result<String, ()> {
    speaker().speak()
}

playground

相反,我收到以下错误:

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>`

就好像编译器无法(此时)推断出 speaker 函数的返回类型。

谁遗漏了什么东西,编译器还是我自己?

最佳答案

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

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

编译器不能在这里推断出任何东西。它无法从调用站点推断错误类型,因为 impl Trait在返回位置不允许从调用站点推断。它无法从实现中推断出错误类型,因为这意味着调用者类型检查是否取决于实现,而这不是 impl Trait 的方式。作品。调用者必须始终在仅存在签名信息的情况下进行类型检查;具体类型仅在此之后插入。

关于rust - 为什么编译器不推断 impl 特征返回值的关联类型的具体类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52831488/

相关文章:

casting - 如何将 &u8 转换为 usize

websocket - 如何识别和删除ws-rs中的闭合连接?

collections - 如何通过结构相等检查结构集合中的结构?

go - 分配空 slice 而不引用其类型?

rust - 创建具有实现某些特征的值的记录器

linux - 是否有比 `std::process::Command` 更低级别的接口(interface)来将单个字符串作为进程执行?

javascript - 重构遗留的基于 mixin 的类层次结构

rust - 为什么 `std::mem::drop` 与高级特征边界中的闭包 |_|() 不完全相同?

swift - "_"类型在快速错误消息中意味着什么?

c# - 线程和委托(delegate)——我不完全理解它们的关系