and then I can use y.borrow_mut() to change the values of the array elements.
Is this correct? Because I think this workaround precludes using #[derive(Default)] on MyStruct, which I would be able to use (I think) without the RefCell, in which case the array would be allocated within the structure.
Is it really impractical or ineffective to allow the declaration of partially mutable objects without the Cell/RefCell constructs?
(My example is slightly different and I didn't test this actual code, so apologies for any mistake.)
There’s no such thing as per-field mutability in Rust. By using interior mutability (eg RefCell) you allow shared/aliased mutation (ie don’t need to hold a &mut). So the consideration here is whether you want to allow this type of mutation or not; it doesn’t really have anything to do with per-field vs whole struct mutability.
does not compile, but changing the array size to 10 does. Some searching showed that Default is implemented for arrays up to 32. Ouch! Should probably give up and implement it in the compiler---at least as a helpful error message.
You're at the mercy of the optimizer here. In particular, debug mode will almost certainly copy. The best you can do is encourage the optimizer to get things right, and use an rvalue (i.e. a temp) instead of binding to a named variable.
On stable Rust, there's not even a way to ensure that Box::new([0u8; 1024 * 1024]) won't first try to create the array on the stack (and possibly overflow it) and then copy it to the heap.
If you're new to Rust and you're not entirely sure you really need an array (e.g. for reading data from C), avoid Rust arrays. They're the least usable type in Rust, and 99% of the time you'll want to use a Vec instead.
In Rust mutability is not the property of data, but the way you access it — whether it's a mutable or immutable reference. Additionally, you can always mutate data you own exclusively (let mut foo = foo makes immutable foo mutable!), so there's no problem in mutating the struct to fill in the data, and then sharing it using immutable reference.
Vec helps in the sense that it's just easier to use and initialize. It can be created with a predefined capacity, too, although it uses the heap. There's also a 3rd party ArrayVec type that stores the vec inline/on stack if you need that.
Without RefCell each piece of data can have only one (exclusive) mutable reference at a time, which is verified at compile time.
RefCell/Cell is to "cheat" the borrow checker to allow multiple mutable references to exist for the same piece of data (you can make a shared "immutable" reference mutable, at cost of a runtime correctness check). It's used for complex cases that borrow checker can't understand. It's also useful to make methods that are logically immutable to the caller, but still need to be mutable in the implementation (e.g. memorization, lazy initialization, caches)