实施 TryFrom/TryInto 特征(而不是 From/Into)

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

我尝试使用 From 特征“重载”一个函数(以便它可以接受一个结构和一个字符串):

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'});
}

根据 Playground,这按预期工作。但是,由于字符串的解析可能会失败,所以我想使用 try_into(),而不是 into()。所以:

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'});
}

问题:

  1. 不幸的是,上面的 error[E0277]: '<T as TryInto<Measurement>>::Error' doesn't implement 'Debug' 失败了。为什么错误类型不等于指定的 String,而是 <T as TryInto<Measurement>>::Error?这个错误类型是什么意思?
  2. 我尝试 let m = Measurement::try_from(value) 而不是 let m = value.try_into()。但是 error[E0277]: the trait bound 'Measurement: From<T>' is not satisfied 失败了,这看起来很奇怪,因为我称之为 try_from(而不是 from)。这是为什么?
  3. 如何正确实现 TryFrom 特性,以便可以按概述处理解析错误?
  4. 为什么我们需要通过 use std::convert::TryFromTryFrom 引入作用域,而 From 特征不需要这个?
  1. 关联类型仍然是泛型,为什么 TryInto<Measurement> 的每个实现都将 String 用于 TryFrom::Error ?按照编译器提示。您可以为 impl TryFrom<i32> for Measurement 或任何使用不同关联类型的实现。
    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. 因为您的绑定是 TryInto<Measurement> 而不是 TryFrom<&str>TryIntoT 实施 TryFrom 时有空白实施,而不是相反。
  3. 你做到了
  4. 因为 Rust 2018 没有将它包含在前奏中,Rust 2021 does