It seems to me that you regard this is a black-and-white, hard "either this XOR that" question.
That's pretty much not the case. I never liked the sort of extremist "thou shalt only use the One True Paradigm™" point of view that certain programming languages (and/or their creators) seem to want to impose on users. For reasons of clarity, performance, maintainability, compatibility, and several others, it's pretty much necessary to mix and match paradigms, and deciding when to use each particular style is part of the tasks of a professional programmer. Yes, sometimes it's hard and there are good arguments in favor of both sides. That's why it is nice to have the choice.
(As an aside, systems programming languages are all about giving and having control anyway. If we have control over ostensibly low-level details such as when to allocate memory, then why not have control over the style as well?)
I also disagree that the ability to mutate std data structures "promotes mutability". Since Rust has value semantics and transitive immutability (for example, you can mutate something through &mut &mut
, but not through &&mut
), the fact that bindings and references are immutable by default means that the instances of your data structures, or rather, the variables through which you access them, also end up being immutable by default. Rust taught us that the best way to reason about mutability in type systems is not by some sort of "intrinsic mutability" of a type or a value, but by the mutability of a specific binding (variable, pattern, …) to that value.
To that end, providing classical vectors, hash tables, etc. doesn't at all hurt or contradict the default of functional and immutable style. And indeed, these compact implementations often have superior performance characteristics (at least in a single-threaded context) compared to the usually tree-based, pointer-hopping persistent data structures. Thus, in my opinion they are the right choice for a systems programming language as practical as Rust.
One other thing that came to my mind is this. I don't think Rust's goal or nature is primarily about promoting functional programming per se. Rust wants to help us write correct, high-quality, easily testable and maintainable software. Functional programming and immutability is not the goal – it is a tool. It did prove to be a very practical means of avoiding certain classes of errors, but it is not the only such technique.
And if we can avoid errors even in the mutable, imperative style by devising clever type checking, and in some cases the imperative code is easier to understand or change, for example, then I think it's completely justified to choose it over immutability. We want to achieve correctness, and we do it in different ways. Sometimes, functional programming and immutability are the best way. In other cases, mutability and imperative programming are the best way. Pick whichever one is warranted by the problem you are solving.