Skip to the content.

Useful Traits

From

Used to do value-to-value conversions while consuming the input value.

It is especially useful when performing error handling. The ‘?’ operator automatically converts the underlying error type with From::from. Here is a snippet from minigrep:

/// takes a configuration and runs the grep functionaly.
pub fn run(config: Config) -> Result<(), Box<dyn Error>> {
    let text = fs::read_to_string(config.file_path)?;

    // --snippet--

    Ok(())
}

The ? operator works for the error type conversion because of the following:

Qeustion :

Does the ? operator automatically call From::from()?

Answer :

The ? operator does not automatically call From::from() on its own; instead, it calls From::from() only when needed to convert between error types — specifically when the error returned by the ? operator does not directly match the function’s return type, but there exists a From implementation between them.

A list just for clear explanation:

✅ The ? operator uses From::from() only when converting between error types.
✅ The error type conversion happens at compile time, relying on the From trait implementation.
✅ If there is no From implementation between the error type returned by the expression and the function’s error type, the compiler gives an error.

Deref

Deref is used for immutable dereferencing operations, like *v. Implementing the Deref trait allows you to Treat Smart Pointers Like Regular References .

It has the concept of deref coercion. Deref coercion is a convenience Rust performs on arguments to functions and methods, and works only on types that implement the Deref trait.

It happens automatically when we pass a reference to a particular type’s value as an argument to a function or method that doesn’t match the parameter type in the function or method definition. A sequence of calls to the deref method converts the type we provided into the type the parameter needs. For example,

use std::ops::Deref;

impl<T> Deref for MyBox<T> {
    type Target = T;

    fn deref(&self) -> &T {
        &self.0
    }
}

struct MyBox<T>(T);

impl<T> MyBox<T> {
    fn new(x: T) -> MyBox<T> {
        MyBox(x)
    }
}

fn hello(name: &str) {
    println!("Hello, {name}!");
}

fn main() {
    let m = MyBox::new(String::from("Rust"));
    hello(&m); // --> deref coercion
    println!("{}", *m); // --> take `m` as regular reference
}

Additional links:

Autodereferencing and autoborrowing