问答

如何在Rust中使用泛型?

作者:admin 2021-09-30 我要评论

比如从一个字符串读入转换为矩阵 struct MatrixT { containner: BoxVecVecT, size: (usize, usize),}impl std::str::FromStr for Matrixi8 { type Err = std::nu...

在说正事之前,我要推荐一个福利:你还在原价购买阿里云、腾讯云、华为云服务器吗?那太亏啦!来这里,新购、升级、续费都打折,能够为您省60%的钱呢!2核4G企业级云服务器低至69元/年,点击进去看看吧>>>)

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

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的官方库确实有很多该有的没有。┑( ̄Д  ̄)┍
###
  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 方法。

版权声明:本文转载自网络,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。本站转载出于传播更多优秀技术知识之目的,如有侵权请联系QQ/微信:153890879删除

相关文章
  • 如何在Rust中使用泛型?

    如何在Rust中使用泛型?

  • Angular8表单值空的问题

    Angular8表单值空的问题

  • eslint为什么会让我给npm install引入

    eslint为什么会让我给npm install引入

  • vue的history模式下如何刷新当前页面?

    vue的history模式下如何刷新当前页面?

腾讯云代理商
海外云服务器