My professional experience with Rust was to build REST and gRPC microservices for a mobile app and its browser admin for over a year. I also contributed to some crate on Github, if only modestly.
What I found the most challenging to learn wasn't really the concept of ownership and borrowing in itself, but more how the whole type system and ecosystem revolves around it. Also a simple thing like what can be done and what shouldn't even be attempted (in the usage of traits and the language in general).
That's actually something I've been trying to write an article about for weeks but still struggle to narrow it down to a "cognitive-friendly" material (I mean, something that doesn't require the reader many hours to read and many days to digest).
Simply because explaining Rust on the surface will still leave a beginner confused as soon as (s)he's digging deeper, but explaining it in details require tremendous amount of explanations and examples.
As much as I love Rust (and wouldn't see myself coding in another language anymore, if not for a living), there's a couple of criticisms I'd like to share :
most of its learning resources are still far too academic for an average person (which contrasts with its empowering everyone aspiration).
➡️ as a mere example, variance, covariance, contravariance and their related explanations are completely appropriate and accurate, but somehow I feel like they could be explained in way simpler terms in general. I think Rust still greatly suffer from a lack of scientific popularization.
part of learning Rust past the basics is actually mastering its (numerous) APIs.
➡️ for example, to be able to return an Option<&T> from a method with an Option<T>, one has to know about as_ref() method. Simply missing it out from the docs or compiler's hints mean that somebody could be mislead in thinking that it's simply not possible at all. Luckily, the community greatly helps here 🥰.
➡️ another example where I think (almost) everyone can relate : making reusable code as a beginner with Diesel can quickly drive you to the verge of insanity 😂.
it's preferable to try an implementation on a bare minimum crate, but one usually has to learn it the hard way as it's not stated clearly enough IMHO.
➡️ for example, when refactoring my code the first time(s) : this is something I'm pretty confident with since I did it countless times with other languages, but with Rust in the beginning I simply lost hours tackling things here and there to please the compiler on each and every nitty-gritty details, almost losing track of what I was doing, but persevering since I thought my idea was correct... just to realize near the end that the compiler would not accept it implemented this way, as it wasn't deemed correct or safe (sometimes also turned out that my attempt was indeed correct, but I was missing the last part of the puzzle, whether it be the use of a certain method in a specific place, or knowing how to deal with some crate's method lifetime). Of course this is desired, and perfectly understandable since the compiler has no way to know what you're trying to achieve, but I wish I was warned right from the beginning not to attempt to do so on large codebase and instead first experiment for feasibility on tiny sample codebase, in order to save on time and frustration. There's no one or nothing to blame here, mistakes were mine, but would it hurt to state it loud and clear in the Rust book ?
These being said, I don't want you to think that this comment is a rant either, simply because Rust compiler already does an astonishing job at assisting the developer on its journey, and its current limitation are not only perfectly understandable, but they keep being pushed over time. Also, as the language becomes more widespread, it will as a matter of fact become more beginner-friendly in terms of learning resources.