如何在Rust中使用泛型?

发布于 2022-09-12 01:01:49 字数 1567 浏览 32 评论 0

比如从一个字符串读入转换为矩阵

struct Matrix<T> {
    containner: Box<Vec<Vec<T>>>,
    size: (usize, usize),
}

impl std::str::FromStr for Matrix<i8> {
    type Err = std::num::ParseIntError;

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let parse_out: Vec<Vec<i8>> = s
            .split(';')
            .map(|i| i.split(',').map(|j| i8::from_str(j).unwrap()).collect())
            .collect();

        let n = parse_out.len();
        let m = parse_out.iter().map(|x| x.len()).max().unwrap();

        let mat = Matrix::<i8> {
            containner: Box::new(parse_out),
            size: (m, n),
        };

        return Ok(mat);
    }
}

在编写这个矩阵时遇到三个问题:

  1. 怎么限制类型Ti8, i16...u8, u16...f32, f64, isize, usize等等一系列数字类型?
  2. 为Matirx实现from_str方法时,如果不具体指定类型,首先type Err无法指定,其次在T::from_str(j).unwrap()时会报错,提示unwrap不一定有实现(这似乎是一个问题?)。如果指定类型,则会有大量代码重复,因为要为每一个类型都重写一遍。
  3. 本身from_str指定了参数和返回类型,但是现在方法中需要额外的参数(行和列的分隔符),应该怎么设计?这里我因作业需要,直接指定为,;了。

想了想了一会,感觉

  1. 类型那个可能需要定义宏???我刚刚看完rust的官方教程,感觉教程上关于宏的内容讲的好少,就是简单提一下。看完好像意思是生成代码的代码。emmm
  2. 如果实在不行,可能还需要自己撸一个num类,以及一系列我觉得该有但是没有的。
  3. crates.io上翻到了num-trait包。看来rust的官方库确实有很多该有的没有。┑( ̄Д  ̄)┍

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

玩世 2022-09-19 01:01:49
  1. 可以通过 marker trait (没有方法、只做标识)实现:

    pub trait Num;
    
    impl Num for i8 {}
    impl Num for i16 {}
    impl Num for i32 {}
    
    pub struct Matrix<T> where T: Num { ... }

    如果不允许其他人扩展,可以参考:Sealed traits protect against downstream implementations (C-SEALED)套一个私有模块。

  2. 可以转成自己的错误类型,也可以这样用直接用已有的错误类型:

    impl<T> std::str::FromStr for Matrix<T> 
      where T: Num + FromStr, <T as FromStr>::Err: std::fmt::Debug {    // 这里
      type Err = <T as FromStr>::Err; // 这里
    
      fn from_str(s: &str) -> Result<Self, Self::Err> {
          let parse_out: Vec<Vec<T>> = s
              .split(';')
              .map(|i| i.split(',').map(|j| j.parse::<T>().unwrap()).collect())
              .collect();
    
          let n = parse_out.len();
          let m = parse_out.iter().map(|x| x.len()).max().unwrap();
    
          let mat = Matrix::<T> {
              containner: Box::new(parse_out),
              size: (m, n),
          };
    
          return Ok(mat);
      }
    }

    建议是用自己的错误类型。

  3. 单独定义一个解析方法,不用硬套到 FromStr 上。例如数字能跟进制解析,所以整数类型都有个单独的 from_str_radix 方法。
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文