我有一个具有相关类型的特征:
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()
}
相反,出现以下错误:
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
函数的返回类型。
谁缺少某些东西,编译器还是我自己?
答案 0 :(得分:6)
使用-> impl Speak<Error = ()>
作为speaker()
的返回类型。
问题在于,编译器仅从签名中就需要调用者可以实际使用该函数的足够信息。如果仅返回impl Speak
,则编译器会知道speak()
返回一个Result<String, ???>
-错误类型未知,因此编译器会发出错误。
编译器无法在此处推断任何内容。它无法从呼叫站点推断错误类型,因为返回位置的impl Trait
不允许从呼叫站点推断错误。它不能从实现中推断出错误类型,因为这将意味着调用者的类型检查是否取决于实现,而这不是impl Trait
的工作方式。调用者必须始终仅在签名信息存在的情况下进行类型检查;在此之后才插入具体类型。
答案 1 :(得分:2)
你是。
您从未指定关联的Error
类型,因此您不能承担任何有关它的假设。即使确实是()
,编译器也不允许您使用这些知识。要解决此问题,只需指定Error
是什么:
pub fn speaker() -> impl Speak<Error = ()> {
Dog::default()
}