let mut url = Url::parse(link)?;
let strip_query_domains = HashSet::from(["zhihu.com", "v2ex.com", "twitter.com"]);
if let Some(Host::Domain(domain)) = url.host() {
if domain == "vxtwitter.com" {
url.set_host(Some("twitter.com"))?;
}
if strip_query_domains.contains(domain) {
url.set_query(None);
}
}
I can understand why this error is happening. And I intended to test the domains after turning the "vxtwitter.com" into "twitter.com".
But how can I fix this without breaking the if let block into two blocks like?
if let Some(Host::Domain(domain)) = url.host() {
if domain == "vxtwitter.com" {
url.set_host(Some("twitter.com"))?;
}
}
if let Some(Host::Domain(domain)) = url.host() {
if strip_query_domains.contains(domain) {
url.set_query(None);
}
}
Hi, sorry for the missing information. The Url struct is from Url in url - Rust .
And I'd like to first transform the vxtwitter.com links into twitter.com, then strip the query together with the links originally twitter.com and other some links.
I'm not sure if I can do that in single if let block when matching the host. Splitting into two block helps, but I will have to add more blocks if there are even some more transformations later.
There's no way to hold on to the domain &str that is borrowed from the Url while also modifying the Url.
It's true more transformations may require more blocks if you keep everything in one function, but as things get long I'd suggest going the opposite direction and encapsulate more into bite-sized functions. E.g.
// This one could grow unbounded as you add replacements, but
// is basically just a list
fn host_replacement(url: &Url) -> Option<&'static str> {
url.host_str().and_then(|host| match host {
"vxtwitter.com" => Some("twitter.com"),
"what.ever" => Some("thing.else"),
_ => None
})
}
// This (optional) one never changes
fn maybe_replace_host(url: &mut Url) -> bool {
if let Some(host) = host_replacement(&url) {
url.set_host(Some(host)).expect("Invalid host");
true
} else {
false
}
}
// Transformations become one-liners where actually used
fn actually_use_it(mut url: Url) {
maybe_replace_host(&mut url);
}
That's precisely because you have to split your code into many separate blocks and maybe even separate functions anyway.
I have seen lots of such scripts in languages where what you are planning to write is possible (JavaScript, Python, etc). And if such script was actually valuable enough to survive a year or two it invariably reaches the state of “it's complete mess, we couldn't touch it anymore without it falling aparts, it's time to throw it away and rewrite from scratch”.
The only way to avoid that fate is to write script like you would write it in Rust: with separate passes and separate functions. And the fact that Rust makes you do that… it's Rust advantage, not weakness.
Now, you may ask: what if I'm writing code for one use and don't plan to keep it around for a year, or two? In that case the advice is just to use not Rust but something else.
While anything can be written in Rust not everything should be written in Rust. Rust doesn't work for quick-and-dirty, let-me-write-and-run-it-once code.
Over time I shift more and more my local scripts to Rust, but JavaScript and Python are still something I reach out for truly write-once-run-once-and-forget cases.