Strings in Rust are (normally) represented as UTF-8. Both `String` and `str` represent data that is guaranteed to be valid UTF-8.
This means that if Rusts UTF-8 strings were represented as normal slices, they would have to be slices of UTF-8 code-units.
Rust wants to provide a safe and correct String data type, and therefore, indexing a string on a byte (code-unit) level would be incorrect behavior.
Having a custom type `String` and `str` instead of just a `Vec<u8>` enables you to have more correct behavior implemented on top of the data type that doesn't implement normal slice indexing and such.
---
As a note, even though you probably don't want to normally, you can quite easily access the backing data of your string using `String::as_bytes`