在上一篇里,定义了一个网格结构
struct Mesh {
points: Vec>, // 点表
facets: Vec> // 面表
}
有什么理由要求 Mesh
的 points
里的各顶点坐标必须是 f64
类型呢?
没有理由,所以 Mesh
结构应该定义为
struct Mesh {
n: usize, // 维度
points: Vec>, // 点表
facets: Vec> // 面表
}
请注意,我还为 Mesh
增加了维度信息。至于 facets
,由于它存储的是顶点在 points
里的下标,有理由要求它是 usize
类型,因为 Vec
的下标就是 usize
类型。
一个向量,其元素为向量,该向量便是矩阵,因此 Mesh
的 points
成员实际上是矩阵,同理,Mesh
的 facets
成员也是矩阵,故而在上一篇里,定义了泛型函数 matrix_fmt
将二者转化为字符串(String
类型)。现在,由于 Mesh
的定义发生了变化,matrix_fmt
也要相应有所变化,借此可再略微温习一遍泛型。
首先,写出一个也许并不正确的 matrix_fmt
:
struct Prefix {
status: bool,
body: fn(&T) -> String
}
impl Prefix {
fn new() -> Prefix {
Prefix{status: false, body: |_| "".to_string()}
}
}
fn matrix_fmt(v: &Vec, prefix: Prefix) -> 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>(v: &Vec,
prefix: Prefix) -> String
where >::Output: fmt::Display,
>::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 fmt::Display for Mesh {
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 {
n: usize, // 维度
points: Vec>, // 点表
facets: Vec> // 面表
}
impl> Mesh {
fn new(n: usize) -> Mesh {
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 = 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 = 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 Length for Vec {
fn len(&self) -> usize {
return self.len();
}
}
struct Prefix {
status: bool,
body: fn(&T) -> String
}
impl Prefix {
fn new() -> Prefix {
Prefix{status: false, body: |_| "".to_string()}
}
}
fn matrix_fmt>(v: &Vec,
prefix: Prefix) -> String
where >::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 fmt::Display for Mesh {
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 = Mesh::new(3);
mesh.load("foo.off");
print!("{}", mesh);
}