why does the value of temporary value drop when the value is borrowed?

When I first tried to reproduce your issue, I got that try_new didn’t exist. It’s been removed in the latest version of lol_html. Replacing it with new, your issue didn’t reproduce. I was able to reproduce with v0.2.0, though. Since the issue had to do with code generated by macros, I tried cargo expand (something you need to install, see here).

Here’s what let handlers = ... expanded to in v0.2.0:

let handlers = <[_]>::into_vec(box [(
    &"a[href]".parse::<::lol_html::Selector>().unwrap(),
    ::lol_html::ElementContentHandlers::default().element(|el| {
        let href = el.get_attribute("href").unwrap().replace("http:", "https:");
        el.set_attribute("href", &href).unwrap();
        Ok(())
    }),
)]);

and here’s what it expands to in v0.3.0

let handlers = <[_]>::into_vec(box [(
    ::std::borrow::Cow::Owned("a[href]".parse::<::lol_html::Selector>().unwrap()),
    ::lol_html::ElementContentHandlers::default().element(|el| {
        let href = el.get_attribute("href").unwrap().replace("http:", "https:");
        el.set_attribute("href", &href).unwrap();
        Ok(())
    }),
)]);

Ignore the first line, it’s how the macro vec! expands. The second line shows the difference in what the versions generate. The first takes a borrow of the result of parse, the second takes a Cow::Owned of it. (Cow stands for copy on write, but it’s more generally useful for anything where you want to be generic over either the borrowed or owned version of something.).

So the short answer is the macro used to expand to something that wasn’t owned, and now it does. As for why it worked without a separate assignment, that’s because Rust automatically created a temporary variable for you.

When using a value expression in most place expression contexts, a temporary unnamed memory location is created initialized to that value and the expression evaluates to that location instead, except if promoted to a static

https://doc.rust-lang.org/reference/expressions.html#tempora...

Initially rust created multiple temporaries for you, all valid for the same-ish scope, the scope of the call to try_new. When you break out the vector to its own assignment the temporary created for element! is only valid for the scope of the vector assignment.

I took a look at the git blame for the element! macro in lol_html, and they made the change because someone opened an issue with essentially your problem. So I’d say this is a bug in a leaky abstraction, not an issue with your understanding of rust.

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top