Apparently, the "let" keyword is needed for parsing so that Rust can have non-trivial patterns on the left hand side of the assignment operator. As in, destructuring binds. I'm assuming you don't know about pattern matching. Pattern matching is a good thing. Maybe even one of the greatest things.
> I’m not a fan of the generics syntax, borrowed from templates in c++ (I prefer the something like the “auto” style more, shifting work to the compiler).
I'm assuming this means you are not a fan of generics. Parametric polymorphism is one of the most powerful things in all of type systems. http://en.wikipedia.org/wiki/Parametricity It's deeply regrettable that not every programming language that exists today has great parametric polymorphism support (Go, I'm looking in your direction). Type parameters and type variable are CRUCIAL for this.
> Forcing the programmer to manually place values on the heap with “~” is annoying, when other languages can automatically optimize such things.
The point of the "~" is to make ownership explicit. C++'s type system is insufficient to make guarantees about ownership. It only recently gained move semantics, which enabled unique pointers, but it makes no guarantees about any other references you make to the object (with the use of .get() and non-smart pointers). As a result, you have to make sure you use C++ smart pointers with discipline. Anytime you are required to do something with discipline, that's an opportunity for a type system to jump in and check your discipline.
> It seems that move semantics distinguish between objects and primitives, instead of everything being an object?
Afaik, in Rust, everything is a primitive, and nothing is an object. What does object even mean?
> Borrow is confusing to me, because I would probably make an immutable object passed to a function as mutable create a copy (but maybe it avoids subtle bugs).
You've never passed anything by reference before? Note that borrowing has less to do with mutability and more to do with ownership discipline.
> Lifetimes completely confuse me, as it seems like they would be handled by garbage collection?
Have you imagined the possibility of a language that does no garbage collection, because it has worked it all out statically? A garbage collector is nothing more than a potentially compile-time problem deferred to run-time. When we moved type-checking from the run-time world to the compile-time world, we gained HUGE benefits in time/space performance and in informing the programmer upfront more about the potential behavior of their program. If only we could do the same thing for memory management. That's what Rust is trynig to achieve.
> I might have gone with traits (interfaces) everywhere instead of distinguishing them from structs, because that seems to be the direction the world is going, to avoid inheritance problems.
Inheritance does cause lots of problems. It's not only that, but Haskell type classes are general and cover lots of real world cases that shitty mainstream type systems can't. One simple example I give is a type-safe .equals method. Java's .equals is type checked ad hoc by the programmer (the argument is an Object, and the programmer typically uses "instanceof" and a cast). You can use generics, but it's still broken, and if someone cares I can go into more detail. Haskell type classes is the only type system I know of where you can just say "hey there's this class of types called 'Eq', where there's a method that takes two arguments of type 'self' and returns a bool". So many OOP type systems only let you have 'this' of type 'self' in a method. I'm handwaving a bit in my description here, but it's a shame this problem isn't just obvious to everyone. Rust is inspired by Haskell type classes, but not fully there.