乐趣区

关于rust:与-Rust-勾心斗角-泛得彻底点儿

在上一篇里,定义了一个网格构造

struct Mesh {
    points: Vec<Vec<f64>>,  // 点表
    facets: Vec<Vec<usize>> // 面表
}

有什么理由要求 Meshpoints 里的各顶点坐标必须是 f64 类型呢?

没有理由,所以 Mesh 构造应该定义为

struct Mesh<T> {
    n: usize, // 维度
    points: Vec<Vec<T>>,  // 点表
    facets: Vec<Vec<usize>> // 面表
}

请留神,我还为 Mesh 减少了维度信息。至于 facets,因为它存储的是顶点在 points 里的下标,有理由要求它是 usize 类型,因为 Vec 的下标就是 usize 类型。

一个向量,其元素为向量,该向量便是矩阵,因而 Meshpoints 成员实际上是矩阵,同理,Meshfacets 成员也是矩阵,故而在上一篇里,定义了泛型函数 matrix_fmt 将二者转化为字符串(String 类型)。当初,因为 Mesh 的定义产生了变动,matrix_fmt 也要相应有所变动,借此可再稍微复习一遍泛型。

首先,写出一个兴许并不正确的 matrix_fmt

struct Prefix<T> {
    status: bool,
    body: fn(&T) -> String
}

impl<T> Prefix<T> {fn new() -> Prefix<T> {Prefix{status: false, body: |_| "".to_string()}
    }
}

fn matrix_fmt<T>(v: &Vec<T>, prefix: Prefix<T>) -> String {let mut s = String::new();
    for x in v {let n = x.len();
        if prefix.status {s += (prefix.body)(x).as_str();}
        for i in 0 .. n {
            if i == n - 1 {s += format!("{}\n", x[i]).as_str();} else {s += format!("{}", x[i]).as_str();}
        }
    }
    return s;
}

通过 rustc 的一番调教,matrix_fmt 最终会变成

fn matrix_fmt<T: Length + Index<usize>>(v: &Vec<T>,
                                        prefix: Prefix<T>) -> String
where <T as Index<usize>>::Output: fmt::Display,
      <T as Index<usize>>::Output: Sized {let mut s = String::new();
    for x in v {let n = x.len();
        if prefix.status {s += (prefix.body)(x).as_str();}
        for i in 0 .. n {
            if i == n - 1 {s += format!("{}\n", x[i]).as_str();} else {s += format!("{}", x[i]).as_str();}
        }
    }
    return s;
}

之所以为 T 减少 fmt::Display 束缚,是因为代码中 format! 的参数是 T。之所以为 T 减少 Sized 束缚,是因为 rustc 心愿可能在编译期间确定 T 的实例占用多少字节的空间。

基于 matrix_fmt 便可为 Mesh 实现 Display Trait:

impl<T: fmt::Display> fmt::Display for Mesh<T> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {let mut info = String::new();
        info += format!("OFF\n").as_str();
        info += format!("{0} {1} 0\n", self.points.len(), self.facets.len()).as_str();
        info += matrix_fmt(&self.points,  Prefix::new()).as_str();
        info += matrix_fmt(&self.facets, Prefix{status: true,
                                                body: |x| format!("{}", x.len())}).as_str();
        write!(f, "{}", info)
    }
}

残缺的代码如下:

use std::fmt;
use std::path::Path;
use std::fs::File;
use std::io::{BufRead, BufReader};
use std::str::FromStr;
use std::num::ParseFloatError;
use std::ops::Index;

struct Mesh<T> {
    n: usize, // 维度
    points: Vec<Vec<T>>,  // 点表
    facets: Vec<Vec<usize>> // 面表
}

impl<T: FromStr<Err = ParseFloatError>> Mesh<T> {fn new(n: usize) -> Mesh<T> {return Mesh {n: n, points: Vec::new(), facets: Vec::new()};
    }
    fn load(&mut self, path: &str) {let path = Path::new(path);
        let file = File::open(path).unwrap();
        let buf = BufReader::new(file);

        let mut lines_iter = buf.lines().map(|l| l.unwrap());
        assert_eq!(lines_iter.next(), Some(String::from("OFF")));
        let second_line = lines_iter.next().unwrap();
        let mut split = second_line.split_whitespace();
        let n_of_points: usize = split.next().unwrap().parse().unwrap();
        let n_of_facets: usize = split.next().unwrap().parse().unwrap();

        for _i in 0 .. n_of_points {let line = lines_iter.next().unwrap();
            let mut p: Vec<T> = Vec::new();
            for x in line.split_whitespace() {p.push(x.parse().unwrap());
            }
            self.points.push(p);
        }
        for _i in 0 .. n_of_facets {let line = lines_iter.next().unwrap();
            let mut f: Vec<usize> = Vec::new();
            let mut split = line.split_whitespace();
            let n:usize = split.next().unwrap().parse().unwrap();
            assert_eq!(n, self.n);
            for x in split {f.push(x.parse().unwrap());
            }
            assert_eq!(n, f.len());
            self.facets.push(f);        
        }
    }
}

trait Length {fn len(&self) -> usize;
}

impl<T> Length for Vec<T> {fn len(&self) -> usize {return self.len();
    }
}

struct Prefix<T> {
    status: bool,
    body: fn(&T) -> String
}

impl<T> Prefix<T> {fn new() -> Prefix<T> {Prefix{status: false, body: |_| "".to_string()}
    }
}

fn matrix_fmt<T: Length + Index<usize>>(v: &Vec<T>,
                                        prefix: Prefix<T>) -> String
where <T as Index<usize>>::Output: fmt::Display {let mut s = String::new();
    for x in v {let n = x.len();
        if prefix.status {s += (prefix.body)(x).as_str();}
        for i in 0 .. n {
            if i == n - 1 {s += format!("{}\n", x[i]).as_str();} else {s += format!("{}", x[i]).as_str();}
        }
    }
    return s;
}

impl<T: fmt::Display> fmt::Display for Mesh<T> {fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {let mut info = String::new();
        info += format!("OFF\n").as_str();
        info += format!("{0} {1} 0\n", self.points.len(), self.facets.len()).as_str();
        info += matrix_fmt(&self.points,  Prefix::new()).as_str();
        info += matrix_fmt(&self.facets, Prefix{status: true,
                                                body: |x| format!("{}", x.len())}).as_str();
        write!(f, "{}", info)
    }
}

fn main() {let mut mesh: Mesh<f64> = Mesh::new(3);
    mesh.load("foo.off");
    print!("{}", mesh);
}
退出移动版