It is possible to embed type alias in a struct in Rust?

Is that possible to embed type alias FooResult into Foo and use it with Foo::Result, so that I don't need to prefix it with Foo?

struct Foo {}
type FooResult = String

// Is it possible to make the type alias FooResult be a static part of Foo, like Foo::Result?

impl Foo {
    // A function for parsing a random string
    // fn parse(input: &str) -> FooResult{
        
    // }
}

#![allow(unused)]
fn main() {
    let result = Foo.parse("hello word");
}

(Playground)

I'm unsure as to what you mean by "embedding" or "static part of". Are you looking for an associated type?

The most straightforward way would be an inherent associated type, used like this: playground. Unfortunately, this isn't possible currently and from a brief glance at the tracking issue, I don't think that it will land soon.

You could achieve it via associated types as mentioned. Alternatively, you could namespace it via modules this way:


pub mod foo {

    pub struct Foo;
    pub type Result = String;
}

// Outside of Foo


pub mod another_module {
    use super::foo::{self, Foo};
    
    fn use_foo(foo: Foo) -> foo::Result {
        todo!()
    }
    
}

(playground)
However this way, foo::Result is not statically linked to the type Foo.

Edit: This is how you could do it with a trait and an associated type:

struct Foo;

trait FooExt {
    type Result;
}

impl FooExt for Foo {
    type Result = String;
}

impl Foo {
    fn parse(input: &str) -> <Self as FooExt>::Result {
        todo!()
    }
}

(playground)
Unfortunately, the <Self as FooExt>::Result is part is necessary. As explained by rustc --explain E0223:

This syntax specifies that we want the X type from MyTrait, as made concrete in
MyStruct. The reason that we cannot simply use MyStruct::X is that MyStruct
might implement two different traits with identically-named associated types.
This syntax allows disambiguation between the two.

To expand on this: given how you want your impl to be "strictly-shaped", it does look like:

which is currently an inherent impl, ought to be a trait impl:

impl Parse for Foo {
    fn parse(input: &str) -> Foo::Result {
        …
    }
}

And, in that case, we can see that Foo::Result is an associated type relative to the Parse trait:

  trait Parse {
+     type Result;

      fn parse(input: &str) -> Self::Result {
  }

And then you can write:

struct Foo {}

impl Parse for Foo {
    type Result = String;

    fn parse(input: &str) -> Self::Result {
        "todo!".into()
    }
}
  • Note that Self::Result, or, more generally, when T : Parse, T::Result is an unambiguous associated type. But if using Foo or some other concrete type, you'll need to use the fully qualified associated type syntax:

    <Foo as Parse>::Result
    

    Which, to be honest, is even better: a Result may be anything, whereas with this syntax it is clear that we are talking of the Result of something related to Parse-ing :slight_smile:

2 Likes