Implementing From trait which returns a mutable ref

Hello everyone,

I'm stuck again with rust lifetimes and traits, I try to implement the From trait:

impl<'a> From<Args> for Aldar<'a> {
    fn from(args: Args) -> Self {
        let al= Aldar::new().case_sensitive(args.ignore_case)
        .show_dirs_only(args.dir_only)
        .do_replace_nonprintable_chars(args.replace_nonprintable)
        .show_hidden(args.all_files)
        .use_max_level(args.level.unwrap_or_else(|| -1))
        .use_glyphset(match args.ascii {
             true => &aldar::ASCII_GLYPHSET,
             false => &aldar::UNICODE_GLYPHSET,
        });
        al
    }
}

I tried a lot of combination but I got always an error, for example:

mismatched types
expected struct `Aldar`, found `&mut Aldar<'_>`rustcE0308
main.rs(90, 28): expected `Aldar<'a>` because of return type

Can someone explain to me, what I'm doing wrong here? My goal is to transform Args into a mutable reference of Aldar. Any hints are very appreciated.

Unless Args already contains such a reference, this won't be possible¹. Unlike most languages with guaranteed-valid references, Rust doesn't extend the life of an object simply because there's a reference to it. Instead, Rust issues a compile error like this one if you try to keep a reference after the object it refers to is destroyed. In your case, the Aldar you create will be destroyed at the end of from(), which leaves the reference you're trying to return dangling.

¹ With the notable exception of deliberately leaking memory. You could, for example, call Box::leak(...) to create a mutable reference to return, but that will prevent the value from ever being freed.


It's hard to say much else without seeing the definition for Aldar and Aldar::new(). Can you post a link to the playground that demonstrates what you're trying to do, and produces a similar error to the one you're getting?

1 Like

Thank you for your input. Here the implementation of the Aldar::new:

impl<'a> Aldar<'a>{
    /// Creates a new Aldar command.
    pub fn new() -> Aldar<'a> {
        let mut default = PathBuf::new();
        default.push(".");

        let current_dir = env::current_dir().unwrap_or(default);
        Aldar {
            show_hidden_files: false,
            dir_only: false,
            ignore_case: false,
            level: -1,
            path: current_dir,
            glyphs: &UNICODE_GLYPHSET,
            output: Box::new(io::stdout()),
            print_fullpath: false,
            print_size: false,
            human_readable: false,
            replace_nonprintables: false,
            exclude_pattern: None,
            include_pattern: None,
            exclude_matcher: None,
            include_matcher: None,
            proc_dirs: 0,
            proc_files: 0,
        }
    }
    
   // Other implementations omitted for brevity
}

I'm not really rely on Form trait, I thought it would be a nice feature and also I can get more familiar with Rust's concepts.

Do you really need a lifetime on Aldar (and if it has one, Args)? It looks like you're only taking references to const or static variables (and that's the only way you could satisfy the signature of new).

If you don't need to hold a shorter-term borrow, consider using &'static inside your struct(s), and removing the lifetime parameter.

2 Likes

Probably not, I'm not sure anymore if it's really necessary. IDE complained because of glyphs (a trait) and output (it's a Writer trait) and it only accepted it with a lifetime.