Course contentsShow
← Rust
Lesson 770 of 1,9106. Generics and Static DispatchFree lesson

Generic Data Normalization

Write conversion utilities that translate between disparate generic input formats.

In this lesson, you will learn how to create flexible conversion utilities that transform disparate generic input formats into a single, standardized internal representation.

The Challenge of Input Variety

In real-world systems, you often receive data from various sources—perhaps a Vec<u8>, a String, or a custom Config struct. Writing a unique function for every possible combination of input types quickly leads to code duplication. Instead, we can use Generic Data Normalization to force these different types into a shared format before processing.

Building a Normalizer

The goal is to define a trait that acts as a "gateway." By implementing this trait for your various inputs, you can write a single generic function that handles the logic, regardless of where the data originated.

Consider this normalization pattern:

trait Normalize {
    fn to_standardized(self) -> Vec<String>;
}

impl Normalize for Vec<&str> {
    fn to_standardized(self) -> Vec<String> {
        self.into_iter().map(|s| s.to_uppercase()).collect()
    }
}

impl Normalize for String {
    fn to_standardized(self) -> Vec<String> {
        vec![self.to_uppercase()]
    }
}

// Our unified processing function
fn process_data<T: Normalize>(input: T) {
    let data = input.to_standardized();
    for item in data {
        println!("Processing: {}", item);
    }
}

Why This Matters

By using a trait as a normalization bridge, you decouple your business logic from the specific storage format of the input. The process_data function doesn't care if the input started as a comma-separated string or a slice of bytes; it only cares that the input knows how to transform itself into your required standard.

This approach ensures that your generic methods remain clean and focused on computation rather than data plumbing. As you add new input sources in the future, you simply implement the Normalize trait for that new type, and your existing processing logic remains entirely untouched.

Key Takeaway: Use trait-based normalization to translate diverse input types into a uniform interface, enabling you to write generic functions that are agnostic of their data source's initial structure.