On this page
Strings and Path
&stris a reference to a byte slice guaranteed to be UTF-8 (String is its heap-allocated version). It cannot be indexed vias[0](because UTF-8 characters are 1-4 bytes, O(1) indexing is not feasible).OsStris the platform-native string (bytes on Unix, WTF-8 on Windows), andPathis a path wrapper aroundOsStr—the correct approach for cross-platform file operations is to always usePath/PathBufrather than string concatenation.
String vs &str: owned vs borrowed
let s: String = Stringfrom; // Heap-allocated, mutable, owned
let r: &str = "hello"; // Static/borrowed, immutable
String = Vec<u8> + UTF-8 validity guarantee—the compiler ensures that the content of String is always valid UTF-8. You can retrieve the underlying Vec<u8> via into_bytes() (discarding the UTF-8 guarantee), or construct from bytes via from_utf8() (which returns a Result; invalid UTF-8 yields an Err).
Why you can't use s[0]
In C, s[0] returns a byte—fine for ASCII, but completely incorrect for multilingual text. In Python, s[0] returns the first Unicode code point—but code points are not always "visible characters" (e.g., é might be represented as e + ́, two code points).
Rust does not expose this access with hidden costs via indexing syntax:
let s = "こんにちは"; // 5 characters, 15 bytes in UTF-8
// let c = s[0]; // COMPILE ERROR: no indexing for String
let c = s.chars.nth.unwrap; // 'に' — O(2): must skip the first 2 characters
UTF-8 is a variable-length encoding: ASCII characters are 1 byte, most Western/Middle Eastern characters are 2 bytes, CJK characters are 3 bytes, and emojis are 4 bytes. s[n] cannot be O(1) in Rust—so it is simply not provided. Programmers must explicitly write .chars().nth(n), acknowledging "this requires scanning."
OsStr/OsString: Non-UTF-8 System Strings
On Unix, filenames are just [u8]—they can be arbitrary bytes and are not guaranteed to be UTF-8. On Windows, filenames are WTF-8 (close to UTF-16). OsStr is a cross-platform abstraction—it does not guarantee UTF-8 content but allows safe passing and concatenation:
use OsStr;
use ;
let p = new;
let parent = p.parent.unwrap; // /usr
let file = p.file_name.unwrap; // bin
let full: PathBuf = p.join.join; // /usr/bin/subdir/file.txt
Path is merely a wrapper around OsStr, adding path-specific methods (parent, extension, components, join). PathBuf is the owned version. The key point is: Path does not require content to be converted to String—you can operate directly on Path without first performing UTF-8 validation.
References
- Rust Book: Chapter 8.2
- Rust Reference: OsStr, Path
Keywords: String, &str, UTF-8, char, OsStr, Path, PathBuf, indexing, Unicode