Trait generic to return Result

How Do I Implement a Generic Result?

    pub type Result<T> = std::result::Result<T, Error>;`

    #[async_trait]
    pub trait CustomerRepo<T> {
        async fn test(&self) -> T;
    }

    pub struct CustomerRepository<'a> {
        pool: &'a PgPool,
    }

    #[async_trait]
    impl<'a> CustomerRepo<Result<T>> for  CustomerRepository<'a> {
        async fn test(&self) -> Result<String> {

            Ok("hi".to_owned())
        }
    }

    |
    | impl<'a> CustomerRepo<Result<T>> for CustomerRepository<'a> {
    |                                   ^ not found in this scope

The names on your example don't line up.

As for your question, you're implementing CustomerRepo<Result<String>>. It's not generic over T. Something like:

#[async_trait]
impl<'a> CustomerRepo<Result<String>> for CustomerRepository<'a> {
    async fn test(&self) -> Result<String> {
        Ok("hi".to_owned())
    }
}

If there is only one logical return from test for any given data type, perhaps you wanted an associated type instead of a generic type. Something like:

#[async_trait]
pub trait CustomerRepo {
    type TestResult;
    async fn test(&self) -> Self::TestResult;
}

#[async_trait]
impl<'a> CustomerRepo for CustomerRepository<'a> {
    type TestResult = Result<String>;
    async fn test(&self) -> Self::TestResult {
        Ok("hi".to_owned())
    }
}

Hi quinedot
I'm going to have several functions, that's why I implemented the generic Result

You should add the generic type T to the impl, which looks like this:

impl<'a, T> CustomerRepo<Result<T>> for  CustomerRepository<'a> {
    // You implementation
}

Hope this will help you.

Hi pangz

impl<'a, T> CustomerRepo<Result<T>> for  CustomerRepository<'a> {
     async fn test(&self) -> Result<String> {
        Ok("hi".to_owned())
    }
}

it generates the following error

    |
    | impl<'a, T> CustomerRepo<T> for CustomerRepository<'a> {
    |          - this type parameter
    |     async fn test(&self) -> Result<String> {
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found enum `std::result::Result`

In your last post, code and error are mismatched. Please, try to create a minimum reproduction, so that we can compile it ourselves and see what went wrong.

1 Like

Sorry for the delayed response.

Your code here is implementing Result<String> rather than a generic result, so I think you don't need the generic T and you may implement this as @quinedot 's answer above.

You seem to be confused as to what generic type parameters mean.

A generic type means a universal quantification. You read impl<T> Trait<T> for Type as "For each possible type, implement the trait Trait parametrized by the type T, for the type Type".

The point of this is that the caller of your function can choose T to be whatever they please at all. (As long as T satisfies the trait bounds placed on it, but in your case, you have none, so there's nothing special to satisfy.) This means that T can be a String, but it can also be an i32, a HashMap<Cow<str>, f64>, or even a CustomTypeNamedAsIfWeWereProgrammingJava. Therefore, it's not possible for the function to return Result<String>, because what would that do if the caller specified another type and not String for the parameter T? It wouldn't make sense.

If you know your function only works if it can always return a String, implement CustomerRepo<Result<String>> instead, as others have mentioned.


Incidentally, if you want to write generic code, but you still want to choose your types, you can reach for associated types. If you think about generics as essentially type-level functions, you can come up with the following analogies:

  • A generic type to types is like a function to values.
  • A generic type parameter to a generic type is like an argument to a function.
  • An associated type to a generic type is like a return value to a function.

For instance, when you are implementing an Iterator, it has to be generic, but at the same time, an iterator doesn't produce any type, it usually produces a single, very specific type. So, its item type is an associated type that you can specify when implementing an iterator:

struct MyReverseRange(u32);

impl Iterator for MyReverseRange {
    type Item = u32;

    // NOW this is the same as `Option<u32>`, because `Item`
    // is *defined* to be the same as `u32` by the impl itself.
    fn next(&mut self) -> Option<Self::Item> {
        if self.0 > 0 {
            self.0 -= 1;
            Some(self.0)
        } else {
            None
        }
    }
}
4 Likes

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.