16.6 String Processing and Parsing

16.6.1 Creating Strings with ToString and Display

To convert any type to a String, you can implement the ToString trait for the type. However, instead of implementing ToString directly, you should implement the fmt::Display trait, which automatically provides an implementation of ToString and allows for the type to be printed using {} in format strings.

Example:

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

Strings are a common source of type conversions, especially when parsing user input, configuration data, or file contents. Rust provides a robust system for string processing using the FromStr trait and the parse method.

The parse method allows strings to be converted into other types that implement the FromStr trait. Most standard library types, such as integers and floating-point numbers, implement FromStr.

Example:

fn main() {
    let num: i32 = "42".parse().expect("Failed to parse string");
    println!("Parsed number: {}", num);
}

In this example:

  • The parse method attempts to convert the string "42" into an i32.
  • If the conversion succeeds, the resulting value is stored in num.
  • If the conversion fails, parse returns an error that can be handled or propagated.

16.6.3 Implementing FromStr for Custom Types

Custom types can implement the FromStr trait to enable parsing from strings. This is especially useful when working with domain-specific data that needs to be converted from textual formats.

Example:

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> {
        // Assume the input is in the format "Name,Age"
        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);
}

In this example:

  • The Person struct represents a person with a name and age.
  • The from_str method parses a string in the format "Name,Age" and constructs a Person.
  • Errors during parsing are handled and propagated appropriately.