nathansizemore
nathansizemore

Reputation: 3196

Defining generic Result<T, E> as return type

I'd like to create a trait that forces the return type of Result<T, E> on some functions, but I cannot figure out the syntax to define this.

I've gotten as far as:

pub type NamedResult<T, E> = Result<T, E>;

pub trait Foo {
    fn bar<T, E>(&self) -> NamedResult<T, E>;
}

pub struct Thing;

impl Foo for Thing {
    pub fn bar<T, E>(&self) -> NamedResult<T, E> {
        Ok(78i32)
    }
}

Produces the following error:

error: mismatched types: 
    expected 'T', 
    found 'i32'
(expected type parameter, found i32) [E0308]

So I then tried:

pub fn bar<i32, String>(&self) -> NamedResult<i32, String> {
    Ok(78i32)
}

And received the following error:

error: user-defined types or type parameters cannot shadow the primitive types [E0317]

What would the proper syntax be so that I can force the implementer of said trait to return a Result<T, E> type on certain functions?

Upvotes: 7

Views: 11318

Answers (1)

Chris Morgan
Chris Morgan

Reputation: 90752

fn bar<T, E>(&self) -> Result<T, E>;

This says that you have a function bar which, given arbitrary types T and E, will return a Result<T, E>. Remember that: the user specifies the type. But what the body of your method is doing is returning a Result<i32, _>, but i32 is not T.

If you wish to specify the type that will be returned, that needs to be specified on the trait implementation, either as a generic or (more normally) as an associated type:

pub trait Foo {
    type Bar;
    type BarError;

    fn bar(&self) -> Result<Self::Bar, Self::BarError>;
}

pub struct Thing;

impl Foo for Thing {
    type Bar = i32;
    type BarError = ();

    pub fn bar(&self) -> Result<i32, ()> {
        Ok(78i32)
    }
}

This way, the user is not specifying the type; rather, when you know that you are calling the bar method on a Thing, you know that the output type will be Result<i32, ()>.

Upvotes: 8

Related Questions