Returning struct<Trait> but with an impl Trait in it

Hi I would like to do something like this:

pub struct Router<G:Graph> {
    graph: G,
}

pub trait Graph {
    fn something();
}

pub struct GraphImpl {

}

impl Graph for GraphImpl {
    fn something() {}
}

impl<G:Graph> Router<G> {
    pub fn new() -> Self {
        let g = create_graph();

        let ret1 = Router {
            graph: GraphImpl{},
        };
        
        let ret2 = Router {
            graph: g,
        };
        
        ret2
    }
}

fn create_graph() -> impl Graph{
    return GraphImpl{}
}

However neither returning ret1 or ret2 seems to work, and I have no idea how to resolve this situation. Any suggestions ?

Thanks in advance

Here you have specified that new() works with any G, but you're trying to return a specific G type, GraphImpl.

The simplest change is to expose the concrete type:

impl Router<GraphImpl> {
    pub fn new() -> Self {
        ...

Now the type will match.

But if you meant from your topic title that you want to hide the graph type, that would have to be a non-associated function (or an associated function with a dummy type parameter not equal to the impl type):

pub fn new_router() -> Router<impl Graph> {
    ...

In both of these cases, note that there is no <G: Graph>. You only use <G: Graph> when you are writing generic code that can work with any Graph type the caller of your function picks.

2 Likes

Okay that makes sense, I guess I am just confused because in my head G means "any implementation of Graph", and impl Graph also meant exactly that.

1 Like

There's a bit of subtlety here because what impl Graph means depends on where it's used.

  • <G: Graph> ... G means that the caller gets to pick some G that implements Graph, and your code must work with that.
  • impl Graph as a function parameter type means the same thing, but without any named type-variable G.
  • impl Graph as a return type means that as the author of the function, you get to pick any one implementation of Graph and return it.

In general, the type notation impl Graph means that the provider of the value gets to pick what the actual type is, and the recipient of the value has to accept it whatever type it is (as long as that type implements Graph). But the consequences of this vary depending on where it's used.

7 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.