A mathematician's perspective
I wanted to share what I think makes Rust special, as a mathematician. I'm not a software engineer, and I can't fully appreciate all the benefits of cargo as a package management system, or how Rust achieves its high performance. I haven't worked with C or C++ yet so I don't fully understand the memory safety nightmares that Rust was built to solve. I just want to talk about the deliberate stylistic choices built into Rust, via an anecdote about teaching calculus.
In my Calculus II class, there was a section on differentiating inverse trig functions. First we had to define the inverse trig functions, and for that we had to cover what it means for a function to have an inverse. Well, a function has an inverse if and only if it's one-to-one. But trig functions are not one-to-one. So what do we have to do? We restrict them, so here are the domains we choose to restrict the trig functions to. It's arbitrary which branch you pick, but we're going to set a convention that these are the restricted trig domains (here are some mnemonics to memorize them). And sin^{-1} is the inverse of the restricted trig function of sine. To make matters juuust a bit worse, our textbook chose a very weird-looking (discontinuous) branch of the secant function so that the derivative of inverse secant would turn out to be something nice. Students were understandably confused.
I thought about why it was that students were confused. Here's the answer I eventually arrived at. Leading up to calculus, we teach students that there is something called the domain of a function. For example, we teach them that the domain of log(x) is the positive reals. What we really mean is that (leave complex numbers aside for the moment) the positive reals is the maximum domain of definition, ordered by inclusion, where we can make sense of taking the log of a real number. When we teach them about real functions, we always just assume it's a function from R to R and wave our hands until we come to a function like log, or square root, or a rational function where the denominator has zeroes, and then we bring up the idea that the function has a domain. Then, since they will be confused by this, we give students a bunch of functions whose domain can't be all of R, compose them in various ways, and ask them to find "the domain" of the composition.
But here's the key point: "log(x)" does not have a domain. "log(x)" isn't even a function; it's just notation so far, we haven't really defined anything. What is a function is log: (0, infinity) -> R. Another function is log: C \ {0} -> C. Yet another function is log: [0.2, 1.76] -> R. At the heart of the students' confusion about inverse trig is the cognitive dissonance of "Wait, you just told us that only one-to-one functions have inverses. But sine's not one to one. But now you're defining inverse sine. And there are more inverse sines depending on something called a 'branch'? What gives?" Because we intentionally conflate sin : R -> R with sin: [-pi/2, pi/2] -> R, when in fact they are different functions! A function is not a formula or "rule" for taking in numbers and spitting out other numbers: it is a set of ordered pairs, and it's not fully defined unless you give the domain, the codomain, and the rule.
Back to Rust. I was working in another language recently, using an API with objects that could either contain an integer, a long integer, or an element of a large prime field. Question: what happens when you multiply two such objects? In my case, in different contexts I had to treat the number inside the object as a bit, as a byte, as a uint64, or as a field element, and in every single case I had to remember what had been put in that object last before I did anything with it. I was constantly worried that I would make some mistake and get some weird unexpected behavior. It was infuriating, because I knew nothing like this would ever happen in Rust. Different types would be treated as different types. At worst I would be dealing with an enum, in which case all the cases would be clearly laid out and I'd just handle them one by one (and it wouldn't compile unless I'd handled them all!).
So what makes Rust special? To me it's this thing that others have written about called the Golden Rule, that function signatures must be declared and followed. Want to know what a function does, what's an acceptable input or output? Look at the signature. You're never stuck there saying to yourself, "Gee, this function could take in an integer, a float, or a string, I wonder what'll happen when I call it. What's in there again?" Same goes for variables. When other languages try to be more user-friendly by guessing what you mean, they're really doing you a disservice. But Rust says, don't leave your readers and the compiler guessing what you just defined: that's error prone. Declare its type immediately. Because you haven't really defined it until you do. This, and the fact that "let" is the keyword to declare new variables (by the way, as someone who reads a lot of proofs, writing this is so satisfying)--it makes me think that Rust's language developers were mathematicians.
Everything is well defined. As it should be.