Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Implementing TryFrom/TryInto trait (instead of From/Into)

I tried to "overload" a function using the From trait (so that it can accept a struct and a string):

pub struct Measurement {
    pub value: i16,
    pub unit: char,
}

impl From<&str> for Measurement {
    fn from(s: &str) -> Measurement {
        let value = s[0..s.len() - 1].parse::<i16>().unwrap();
        let unit = s.chars().last().unwrap();

        return Measurement { value, unit };
    }
}

pub fn print_measurement<T: Into<Measurement>>(value: T) {
    let m = value.into();
    println!("Measurement is {}{}", m.value, m.unit);
}

fn main() {
    print_measurement("40m");
    print_measurement(Measurement{value: 23, unit: 'g'});
}

As per Playground, this works as expected. However, since parsing of the string can fail, I wanted to use try_into(), instead of into(). So:

use std::convert::TryFrom;

#[derive(Debug)]
pub struct Measurement {
    pub value: i16,
    pub unit: char,
}

impl TryFrom<&str> for Measurement {
    type Error = String;

    fn try_from(s: &str) -> Result<Measurement, String> {
        let value = s[0..s.len() - 1].parse::<i16>();
        let unit = s.chars().last();
        match (value, unit) {
            (Ok(v), Some(u)) => Ok(Measurement { value: v, unit: u }),
            _ => Err("Invalid value or unit".to_string()),
        }
    }
}

pub fn try_print_measurement<T: TryInto<Measurement>>(value: T) {
    let m = value.try_into();
    match m {
        Ok(m) => println!("Measurement is {}{}", m.value, m.unit),
        Err(e) => println!("Error when parsing: {:?}", e),
    }
}

fn main() {
    try_print_measurement("4_0m"); // <-- this line should fail to parse
    try_print_measurement(Measurement{value: 23, unit: 'g'});
}

Questions:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

  1. Unfortunately, the above fails with error[E0277]: '<T as TryInto<Measurement>>::Error' doesn't implement 'Debug'. Why isn’t the error type equal to String as specified, but rather <T as TryInto<Measurement>>::Error? And what does this error type mean?
  2. Instead of let m = value.try_into() I tried let m = Measurement::try_from(value). But this fails with error[E0277]: the trait bound 'Measurement: From<T>' is not satisfied, which seems odd as I call try_from (and not from). Why is that?
  3. How would one correctly implement the TryFrom trait, so that the parsing errors can be dealt with as outlined?
  4. Why do we need to bring TryFrom into scope via use std::convert::TryFrom, whereas the From trait does not require this?

>Solution :

  1. associated type are still generic, why every implementation of TryInto<Measurement> would use String for TryFrom::Error ? Follow compiler hint. You could have an implementation for impl TryFrom<i32> for Measurement or whatever that use different associated type.
    pub fn try_print_measurement<T>(value: T)
    where
        T: TryInto<Measurement>,
        <T as TryInto<Measurement>>::Error: std::fmt::Debug,
    {
        let m = value.try_into();
        match m {
            Ok(m) => println!("Measurement is {}{}", m.value, m.unit),
            Err(e) => println!("Error when parsing: {:?}", e),
        }
    }
    
  2. cause your bound is TryInto<Measurement> not TryFrom<&str>. TryInto have blanked implementation when T implement TryFrom, not the opposite.
  3. you did
  4. cause Rust 2018 didn’t include it in prelude, Rust 2021 does
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading