Work with Strings and Slices

RustBeginner
Practice Now

Introduction

Rust uses String for owned, growable text and &str for a borrowed view of text. A string slice can view an entire string or a selected byte range without copying its characters.

You will pass owned text to a function that borrows &str, create a borrowed command keyword, and intentionally ask the compiler to index UTF-8 text in an unsupported way before repairing it with a valid boundary-aware slice.

Borrow Owned and Literal Text as &str

In this step, you will pass two different text sources to one function that accepts a borrowed string slice.

Enter the prepared project and open its source:

cd /home/labex/project/string-slices
nano src/main.rs

The type String owns growable text. The type &str, pronounced “string slice,” is a borrowed view into valid UTF-8 text. A string literal such as "preview" already has a borrowed string-slice type because the program stores its text for the entire run.

The function show_text(label: &str) can view either kind of text. Replace only /* Step 1: borrow command */ with &command:

    show_text(&command);

Rust automatically treats the borrowed &String as the &str view the function requests. This conversion does not copy or move the characters.

Save with Ctrl+O, press Enter, and exit with Ctrl+X. Run the program:

cargo run --quiet

The output should be:

Text: serve reports
Text: preview
Keyword: <>
Status: ✅ ready

Both calls reach the same &str parameter. The empty keyword is a prepared placeholder for the next step.

Borrow a Substring Without Copying

In this step, you will make keyword view only the serve prefix inside command.

Open the source:

nano src/main.rs

The slice form &text[start..end] borrows a range. The start is included and the end is excluded. Rust string ranges count bytes, and the ASCII letters in serve each occupy one byte, so the range begins at byte 0 and ends before byte 5.

Replace only the empty literal "" on the Step 2 line with &command[0..5]:

    let keyword = &command[0..5]; // Step 2: replace the empty slice.

The resulting &str points into command; it does not allocate or copy a second string. Because command remains in scope, the borrowed view stays valid while keyword is used.

Save and exit, then run:

cargo run --quiet

The final line should now be:

Keyword: <serve>

The owned command still contains the complete serve reports text, while keyword is only a borrowed window into its first five bytes.

Respect UTF-8 Character Boundaries

In this step, you will intentionally try integer indexing, read the compiler's explanation, and replace it with a valid UTF-8 slice.

UTF-8 characters do not all occupy one byte. In "✅ ready", the check-mark symbol uses three bytes. Therefore byte zero is not automatically “the first character,” and Rust does not allow status[0] on a String.

Open the file and remove only the leading // from the Step 3 print line:

nano src/main.rs

Save and exit, then run the check. Failure is expected:

cargo check

Find the stable message:

error[E0277]: the type `str` cannot be indexed by `{integer}`

The diagnostic protects you from pretending every character has a one-byte position. Open the file again and replace that failing print line with these two short lines:

    let symbol = &status[0..3];
    println!("Status symbol: {symbol}");

The range 0..3 ends exactly after the three-byte symbol. This works because the prepared text and its byte boundary are known in advance; it is not a general recipe for finding the first human-visible character in arbitrary text. A range that cuts through the middle of a UTF-8 character would panic at runtime, so string ranges must come from known valid boundaries.

Save and exit, then check and run:

cargo check
cargo run --quiet

The complete output should be:

Text: serve reports
Text: preview
Keyword: <serve>
Status: ✅ ready
Status symbol: ✅

The successful output proves that the final slice selects one complete UTF-8 character without copying the original String.

Summary

You connected owned String values and borrowed &str views, selected a substring without allocation, and learned why UTF-8 text cannot be treated as a byte-indexed character array. Safe string ranges must begin and end on valid UTF-8 boundaries.