16.6 String Processing and Parsing

Real-world programs often convert strings into other data types, especially when reading user input or configuration files. Rust provides traits like Display, ToString, and FromStr to streamline these conversions.

16.6.1 Creating Strings with Display and ToString

If you implement the Display trait (from std::fmt) for a custom type, you automatically get ToString for free:

use std::fmt;

struct Circle {
    radius: i32,
}

impl fmt::Display for Circle {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "Circle of radius {}", self.radius)
    }
}

fn main() {
    let circle = Circle { radius: 6 };
    println!("{}", circle.to_string());
}

16.6.2 Converting from Strings with parse

Most numeric types in the standard library implement FromStr, enabling .parse():

fn main() {
    let num: i32 = "42".parse().expect("Cannot parse '42' as i32");
    println!("Parsed number: {}", num);
}

16.6.3 Implementing FromStr for Custom Types

You can define FromStr to handle custom parsing:

use std::str::FromStr;

#[derive(Debug)]
struct Person {
    name: String,
    age: u8,
}

impl FromStr for Person {
    type Err = String;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parts: Vec<&str> = s.split(',').collect();
        if parts.len() != 2 {
            return Err("Invalid input".to_string());
        }
        let name = parts[0].to_string();
        let age = parts[1].parse::<u8>().map_err(|_| "Invalid age".to_string())?;
        Ok(Person { name, age })
    }
}

fn main() {
    let input = "Alice,30";
    let person: Person = input.parse().expect("Failed to parse person");
    println!("{:?}", person);
}