4 ms·
I 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 m
by hawski 5y ago
I 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...
- hawski 5y agoNo offense taken. The code dump is pretty unfriendly. I dabbled with it more around version lol_html 0.2 and afterwards not that much. Partially, because I felt dumb. Still I feel like I need to look into documentation almost for every dot in the code. Thank you, especially for your thorough investigation! I thought that the macro could do something funky, but didn't know about `cargo expand`. That is a very useful thing to know. Is there a good write up about such intricacies like Cow::Owned? I would think that the problem is probably something that people may have from time to time. Was there a way to wrap every element in something to make it work with the old version?
- iudqnolq 5y agoTo be honest lol_html looks like either someone new to Rust who got excited by the opportunity to do a lot of premature optimization or someone with very very intense perf needs. I strongly recommend to work with owned data whenever possible and clone freely. It's also macro heavy for something that doesn't seem like it should need to be. It's normal to need to constantly check the docs with macros, since they're their own language. EDIT: I realized it's by cloudflare. The architecture makes sense in terms of their needs.