Start learning free

LESSON 68 OF 414 · STRINGS I

String Split in Rust: split and collect

Lesson Read the full explanation

In Rust, you can split a string into a vector of words by whitespace using the .split_whitespace() method and .collect():

// split_whitespace() splits a string into words by whitespace
let sentence = "hello world foo";
let words: Vec<&str> = sentence.split_whitespace().collect();
// words == ["hello", "world", "foo"]

Here is how the split works internally:

// split_whitespace() returns an iterator over substrings
// .collect() gathers the iterator into a Vec<&str>
let sentence = "hello world foo";
let words: Vec<&str> = sentence.split_whitespace().collect();

Assignment
Follow the Coding Tutorial and split sentence into a vector of words!


Hint
Use sentence.split_whitespace().collect() and assign the result to words, declared with the type Vec<&str> so that collect() knows what to build.

STEP 1 OF 1
    Ctrl + Enter to check

    RUST · STRINGS I

    String Split in Rust, explained

    Splitting a string into pieces

    Splitting cuts a string at every separator and gives you the pieces between them. In Rust, split is a method on str that takes the separator:

    let sentence = "hello world foo";
    let words: Vec<&str> = sentence.split(" ").collect();
    println!("{:?}", words);
    
    ["hello", "world", "foo"]
    

    Two things in that code deserve a closer look: why collect() is needed, and what the type Vec<&str> means.

    Why collect() is needed

    split doesn't return a vector. It returns an iterator, a lazy object that produces the pieces one at a time as you ask for them. Nothing is cut until you consume it. collect() consumes the iterator and gathers its items into a collection.

    Which collection? collect() can build many, so Rust needs to be told. Here the annotation on words does it: Vec<&str>. Without any type information, the compiler reports that it can't infer the type. You can also give the type to collect itself: sentence.split(" ").collect::<Vec<&str>>().

    If you only need to walk through the pieces once, skip collect and loop over the iterator directly:

    for w in sentence.split(" ") {
        println!("{}", w);
    }
    

    What Vec<&str> means

    Each piece is a &str, a borrowed view into the original string. No new strings are allocated for the pieces, which makes splitting cheap. The price is that the pieces can't outlive sentence. If you need strings that stand on their own, convert each piece, for example with .map(|w| w.to_string()) before collecting into a Vec<String>.

    Separators and their quirks

    The separator can be a string slice or a single char, so split(',') works for comma-separated text. Keep these behaviours in mind:

    • Consecutive separators produce empty pieces. "a b c".split(" ") yields ["a", "", "b", "", "", "c"], because there is an empty string between every two adjacent spaces.
    • The same goes for separators at the ends. "a,b,,c".split(',') yields ["a", "b", "", "c"].
    • An empty input still yields one piece. "".split(" ") gives [""], a vector with one empty string, not an empty vector.

    split_whitespace

    For splitting text into words, split_whitespace() is usually the better tool. It splits on any run of whitespace (spaces, tabs, newlines) and ignores leading and trailing whitespace, so it never produces empty pieces:

    let words: Vec<&str> = "a  b   c".split_whitespace().collect();
    println!("{:?}", words);
    let none: Vec<&str> = "".split_whitespace().collect();
    println!("{:?}", none);
    
    ["a", "b", "c"]
    []
    

    For the single-spaced sentence in this lesson, split(" ") and split_whitespace() give the same result. They differ as soon as the spacing is irregular.

    Other ways to split

    Besides split and split_whitespace, a few related methods are worth knowing:

    • lines() splits on line breaks and is the right choice for multi-line text.
    • splitn(n, sep) stops after n pieces, leaving the rest of the string in the last one.
    • split_once(sep) cuts at the first separator only and returns an Option holding the two halves, which suits key=value text: "name=Ana".split_once('=') is Some(("name", "Ana")).
    • chars() splits a string into characters rather than by a separator.

    A Vec lets you use the pieces by position. words[0] is the first word, words.len() is how many there are, and indexing past the end panics, so use words.get(i) when the position might not exist.

    The exercise

    The starting code contains only the loop that prints each word, so the variables have to be added above it:

    1. Declare sentence with let, holding "hello world foo".
    2. Declare words with the type Vec<&str>.
    3. Build it by calling .split(" ") on sentence and finishing with .collect().
            let sentence = "hello world foo";
            let words: Vec<&str> = sentence.split(" ").collect();
            for w in &words {
                println!("{}", w);
            }
    

    The loop borrows the vector with &words, so words is still usable afterwards. Looping over words without the & would move the vector into the loop. Each w is a &&str here, and println! prints it like a plain string. The output is one word per line:

    hello
    world
    foo
    

    Key takeaways

    • split returns a lazy iterator, and collect() gathers it into a collection chosen by the type annotation.
    • The pieces of a Vec<&str> borrow from the original string, so nothing is copied.
    • Repeated separators give empty pieces; split_whitespace() avoids them.
    • Splitting an empty string with split gives one empty piece.
    • Loop over &words to keep the vector usable afterwards.
    Keep going with RustAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free