But to answer your question about copies : Rust is a move-only language, copies are actually called `.clone()`, except for a few types which are cheap enough to copy that they implement the `Copy` trait.
So in the code you quoted, the match is done on the value of `result` (notice that there is not borrowing/`&` operator). The match arm `Err(err)` moves `err` out of `result` and returns it. Obviously, the compiler will optimize away all those moves, it's as if they did not exist.
This is almost true, but not exact. Copy is for everything where cloning is just memcopy, that doesn't means it's necessarily cheap ([42;4_000_000] implements Copy, yet it's not cheap to copy at all…).
And moving things sometimes (but not always) means the thing is getting memcopied (or it could use a pointer, depending on the optimizer's m̶o̶o̶d̶ euristics)
It sounds like this is coming from a C++ bias? So please forgive me if this is wrong.
Rust, in my experience, favors move semantics first, then copy semantics after.
I know in C++, we had implicit copy constructors, with move semantics after with rvalue references, where you need to use `std::move` in a lot of cases.
So what helps, in my opinion, is to think of Rust as using `std::move` as a default.
Even more than that, with the exception of types that implement `Copy` (e.g. bools, integers, etc.), using after a move won't just silently degrade to a copy, but will cause a compiler error. Copying is required to be explicit for all but the most trivial types.
You would think wrong. In Rust, everything is move by default. To create a copy, you need to explicitly call .clone() on an object (assuming it implements Clone, of course), or you can implement Copy for the type, which will cause .clone() to be called instead of moving the value.
(I'm not actually sure where the compiler will generate calls to clone() on Copy types in favor of moving. In practice, you're not going to implement Copy for a type that isn't trivially copyable anyways [using the C++ definition], so any optimizer would easily be able to elide any excessive copy operations.)
The docs for the trait (core::marker::Copy) are pretty good
It’s not because of the borrow checker, it’s because Rust defaults to (destructive) moves, and implicit copies can only be trivial.
Any non-trivial copy has to go through an explicit clone() instead.
let response = reqwest::blocking::get(url)?;
In the way written there's no additional copy.
(Also, for those unfamiliar with it: reqwest is not a typo. See https://github.com/seanmonstar/reqwest)