Почему компилятор не выводит конкретный тип ассоциированного типа возвращаемого значения impl trait? - PullRequest
0 голосов
/ 16 октября 2018

У меня есть черта со связанным типом:

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.

Кто-то что-то упустил, компилятор или я?

Ответы [ 2 ]

0 голосов
/ 16 октября 2018

Используйте -> impl Speak<Error = ()> в качестве типа возврата speaker().

Проблема заключается в том, что компилятору требуется только от одной подписи достаточно информации, чтобы вызывающий мог фактически использовать функцию.Если вы просто вернете impl Speak, то компилятор знает, что speak() возвращает Result<String, ???> - тип ошибки неизвестен, и, следовательно, компилятор выдает ошибку.

Компилятор не может вывести здесь ничего,Он не может определить тип ошибки с сайта вызова, потому что impl Trait в обратной позиции не позволяет сделать вывод с сайта вызова.Он не может вывести тип ошибки из реализации, потому что это будет означать, зависит ли проверка типов вызывающей стороны от реализации, а это не так, как работает impl Trait.Звонящий должен всегда проверять тип при наличии только информации о подписи;тип бетона включается только после этого.

0 голосов
/ 16 октября 2018

You are.

Вы никогда не указывали связанный тип Error, поэтому вы не можете предполагать что-либо об этом.Даже если это действительно (), компилятор не позволит вам использовать эти знания.Чтобы решить эту проблему, просто укажите, что такое Error:

pub fn speaker() -> impl Speak<Error = ()> {
    Dog::default()
}
...