It's less about security or safety and more about how arrays simply work.
That is not to say, certainly it can also be a memory safety related thing: Having the concept of a "fixed size array" allows function signatures to specify exactly how many elements they want, within the function, bounds checks for constant indices could be optimized away, APIs can be harder to misuse of they're able to enforce array lengths, etc… And once you've established this restriction, of course it must be rigorously enforced for type safety.
However, there's another aspect, and in many Rust programmer's minds, this will be the true reason: It's about how arrays work. Arrays are a very simple datatype in Rust. A value of type, say,
[T; 3] consists simply of 3 values of type
T stuck together in memory, right next each other. Notably, handling an array does mean, you handle these values directly. No pointers, no heap data, no length information, no overhead. If you have a
[T; N] on a local variable, then those
N amount of
Ts will sit directly on your stack memory, taking up
N * mem::size_of::<T>() space, and for something to be allowed to sit on the stack, its size needs to be fixed and determined at compile-time.
There exist other types that are different. If you still want a fixed size limit so things can lay on the stack, but are fine with the overhead of saving the length information at run time, too, to gain flexibility in the actual length, then something like ArrayVec in arrayvec - Rust does that.
If you want no length limitation but in turn are fine with moving the data into the heap, then
Vec<T> is the most commonly used type for that. If you have the data behind some level of indirection anyways, then slices are a powerful tool to make length flexible, as well as to abstract over the data in (borrows of) various other data structures including all the ones mentioned before, i. e. arrays,
Vec, and more.