3 ms·
I still couldn't get or understand an answer to this question: https://stackoverflow.com/questions/64705654/why-i-get-temporary-value-dropped-while-borrowed-if-
by hawski 5y ago
I still couldn't get or understand an answer to this question: https://stackoverflow.com/questions/64705654/why-i-get-temporary-value-dropped-while-borrowed-if-i-assign-but-not-when-pas https://stackoverflow.com/questions/64705654/why-i-get-tempo...
Why I can put a temporary inside a single expression, but if I bind it first just to move it inside I'm not allowed?
This works:
use lol_html::{element, HtmlRewriter, Settings};
let mut output = vec![];
{
let mut rewriter = HtmlRewriter::try_new(
Settings {
element_content_handlers: vec![
// Rewrite insecure hyperlinks
element!("a[href]", |el| {
let href = el
.get_attribute("href")
.unwrap()
.replace("http:", "https:");
el.set_attribute("href", &href).unwrap();
Ok(())
})
],
..Settings::default()
},
|c: &[u8]| output.extend_from_slice(c)
).unwrap();
rewriter.write(b"<div><a href=").unwrap();
rewriter.write(b"http://example.com>").unwrap();
rewriter.write(b"</a></div>").unwrap();
rewriter.end().unwrap();
}
assert_eq!(
String::from_utf8(output).unwrap(),
r#"<div><a href="https://example.com"></a></div>"#
);
With the temporary vec moved outside it errors with "temporary value dropped while borrowed" on the "let handlers" line.
use lol_html::{element, HtmlRewriter, Settings};
let mut output = vec![];
{
let handlers = vec![
// Rewrite insecure hyperlinks
element!("a[href]", |el| {
let href = el
.get_attribute("href")
.unwrap()
.replace("http:", "https:");
el.set_attribute("href", &href).unwrap();
Ok(())
}) // this element is deemed temporary
];
let mut rewriter = HtmlRewriter::try_new(
Settings {
element_content_handlers: handlers,
..Settings::default()
},
|c: &[u8]| output.extend_from_slice(c)
).unwrap();
rewriter.write(b"<div><a href=").unwrap();
rewriter.write(b"http://example.com>").unwrap();
rewriter.write(b"</a></div>").unwrap();
rewriter.end().unwrap();
}
assert_eq!(
String::from_utf8(output).unwrap(),
r#"<div><a href="https://example.com"></a></div>"#
);
- iudqnolq 5y agoYou got a pretty good answer on stackoverflow, despite a not very good question. You could try a follow up question on the rust discord, but I'd suggest massively decreasing the size of the code dump, and talking about why the proposed solution doesn't work.
- hawski 5y agoI agree that the question is not very good. It is hard to make a smaller code dump, when I'm at this stage of learning the language, because I don't know what matters. Answers do not help me to understand the difference and do not clear the confusion. What they suggested was suggested by the compiler. It does work, when I have a call like that: func(vec![element!(...)]); But if I put the vec outside it will complain about temporary element!(...): let v = vec![element!(...)]; func(v); Answers and the compiler suggest the following: let e = element!(...); let v = vec![e]; func(v); This however is problematic if you have many elements in the vec. It also does not answer to me how is that significant. For me if I can pass a temporary to a function, why can't I bind the temporary to the vec? The why is important to me. I would like to make second form work. I don't deride people that answered me, I asked a few clarification comments, but I've got no follow-up or a follow-up that still doesn't answer the question. It is a good solution, but I don't understand why I have to go this way and the obvious one for me doesn't work.
- iudqnolq 5y agoI apologize. I skimmed your post and the response and fit it into some stereotypes. Your question is actually a lot more interesting than I thought. I couldn't figure it out reading the docs on my phone. 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 [1]). 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#temporaries 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[2] 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. [1]: https://github.com/dtolnay/cargo-expand https://github.com/dtolnay/cargo-expand [2]: https://github.com/cloudflare/lol-html/commit/e0eaf6c4234af855d3b77e6cb1731f5f33d0d6fb https://github.com/cloudflare/lol-html/commit/e0eaf6c4234af8...