Implement a Method Returning Self for a Struct with a Reference

Suppose that I've written something roughly like this:

pub trait Tr { 
    fn form(a: &dyn Fn(usize)) -> Self; 
} 

pub struct Str<'t> { 
    func: &'t dyn Fn(usize), 
} 

impl<'t> Tr for Str<'t> { 
    fn form(a: &dyn Fn(usize)) -> Self { 
        let res: Self = Str { func: a }; 
        return res; 
    } 
} 

Now, if there is no clear specification as to the lifetime of the parameter a in the implemented method, there would be an error.

But rust would still report an error, complaining that res doesn't have the expected type Self when a lifetime is made explicit as well, just because the Self at the return type of the method form may not have the same lifetime as that of a.

How do I implement a method with Self as the return type for a type with a lifetime paramter -- when the method should construct a new instance of Self and return it (like what is intended to be done in the above example)? I'm trying to get around a similar problem in a project, in which the specific trait cannot be made into a trait object. Please forgive me if this is a dumb question, I'm only starting to learn rust XD.

Make the function take &'t dyn Fn(usize), so that it returns 't-bound value. Alternatively, you can also write full type name instead of Self alias. Self isn't a different type, just a syntax sugar.

Thank you, @kornel ! This does solve the matter at hand. Although...

In the trait I defined, there are also methods with default implementations of the form

pub trait Tr { 
    ... 
    fn method(&self, rhs: Self) { 
        form(
            &| param: usize | { /* something involving rhs */ }
        )
    }
}

The default implementation for such methods, when an explicit lifetime for form is specified, would be marked as erroneous with an error code E0716 "temporary value dropped while borrowed" accross the trait -- is the "temporary value" in the message referring to the closure literal, indicating that I wouldn't be able to feed closure literals directly to a call to form?

If you meant something like

impl<'lt> Tr<'lt> for Str<'lt> {
    fn form(&'lt dyn FnOnce(usize)) -> Self { ... }
    fn method(&self, rhs: Self) {
        local = |_| {};
        let _ = Self::form(&local);
    }
}

Then if we expand some lifetimes we can see...

impl<'lt> Tr<'lt> for Str<'lt> {
    fn form(&'lt dyn FnOnce(usize)) -> Str<'lt> { ... }
    fn method(&self, rhs: Self) {
        local = |_| {};
        let _ = Str::<'lt>::form(&local);
    }
}

And this is analogous to something like

fn f<'caller_chosen>(_: &'caller_chosen str) {
    let local = String::new();
    let _: &'caller_chosen str = str::trim(&local);
}

Wherein you're trying to borrow a local variable for some arbitrarily long lifetime.


Possible out number 1

Similar to how static promotion can give you a 'static lifetime for literals:

fn g<'caller_chosen>(_: &'caller_chosen usize) {
    // let local = 0;
    // let _: &'caller_chosen usize = &local;
    let _: &'caller_chosen usize = &0;
}

Closures which do not capture their environment can be coerced into lifetime-unencumbered function pointers:

    fn method(&self, rhs: Self) {
        // local = |_| {};
        // let _ = Str::<'lt>::form(&local);
        let _ = Str::<'lt>::form(&|_| {});
    }

Playground. But this won't work if your closure captures things.


Possible out number 2

Maybe you don't need the newly-formed Str<'_> to be the same as Self. Then you could do

    fn method(&self, rhs: Self) { 
        let local = |_| {};
        let _ = Str::<'_>::form(&local);
    }

Playground.


Probable actual solution

References are typically for short-lived borrows. Box up your dyn FnOnce instead, so you own them.

Playground.

You need to think where the data for the borrowed references is permanently stored. References can't exist on their own. They don't have any data, they only give permission to access data somewhere else.

In case of rhs, it could be stored either in the function argument, or moved into the closure.

If it's borrowed from the function argument, then any object using it can never leave the function. That's because function arguments are like local variables, and get destroyed by the end of the function. So you can't return anything borrowing a function argument.

It could be moved to the closure, so that the closure will own the rhs value. However, then the question becomes — where is the closure stored? If you use &|| then the answer is nowhere, and you have another problem. That temporary closure, and everything it owns, will be destroyed at the end of the call that uses it.

You could use rhs: &Other, and then that Other would be stored somewhere else, outside your function call, so it's not your problem. You only need to declare that your function's output reuses function's input.

But rhs: Something gives up ownership of Something, and it's up to you to store it somewhere.

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.