Returning struct with trait object from function

I want to refactor some codes from using Box, to using trait object.

This code:

trait Foo {}

struct MyFoo;

impl Foo for MyFoo {}

struct Bar<'a> {
    foo: &'a (dyn Foo + 'a),
}

fn create_bar<'a>() -> Bar<'a> {
    let foo = MyFoo {};
    Bar { foo: &foo }
}

fn main() {
    let _mybar = create_bar();
}

Will not compile with error message.

cannot return value referencing local variable `foo`

You can't return a value that borrows from a local variable of the function because that value will be destroyed when it goes out of scope. You have to return an owned value (e.g. a Box) in this case.

2 Likes

Can I do something like that without using Box?

This foo has to live somewhere as long as the Bar it is in lives. It doesn't matter whether you use Box or something else.

You may pass the foo as a parameter to the create_bar for solving the lifetime problem. Or you may make the Bar struct own the local foo instead of borrowing it.

It depends on what you're trying to achieve and why you want to get rid of Box.

You can use smallbox instead of Box to avoid an allocation if your objects are small.

You can leak the Box and return the produced static reference if you don't need to ever delete the object.

You can refactor your code so that you don't return the borrowed value at all, instead you just store it locally and pass it to somewhere by reference to process it while it's still in scope:

fn main() {
    let foo = MyFoo {};
    let bar = Bar { foo: &foo };
    work_with_bar(bar);
}
1 Like

For better performance.

Box is not less performant in usage then references, since both are compiled down to plain pointers (or fat pointers, in case of trait objects). The only performance hit is during the allocation, since value must be first created on stack and then moved to heap.

1 Like