gpt4 book ai didi

polymorphism - 在 Rust 匹配表达式中保持 DRY

转载 作者:行者123 更新时间:2023-11-29 08:30:20 24 4
gpt4 key购买 nike

作为一个简化的、独立的示例,假设我正在解析一个充满形状定义的输入文件:

// shapes.txt
Circle: radius 1, color blue
Square: edge 5, color red
Triangle: edge 2 , color black
Triangle: edge 2 , color white

我想将它们解析成如下结构:

struct Circle {
radius: i32,
color: String
}

struct Square {
edge: i32,
color: String
}

struct Triangle {
edge: i32,
color: String
}

我想将它们解析为一组特定于形状的向量,例如:

CircleDb: Vec<Circle>;
TriangleDb: Vec<Triangle>;
SquareDb: Vec<Square>;

...使用像这样的匹配 block :

match inputFile.nextWord() {
"Circle" => {
Circle c = parseCircle(inputFile);
CircleDb.push(c);
},
"Square" => {
Square s = parseSquare(inputFile);
SquareDb.push(s);
},
"Triangle" => {
Triangle t = parseTriangle(inputFile);
TriangleDb.push(t);
},
}

现在,想象一下,我有 10 种或 15 种形状,而不是 3 种形状。所以我不想重复 x=parseX(inputFile); 的相同序列; XDb.push(x); 在每个分支中。我宁愿这样说:

let myMatcher = match inputFile.nextWord() {
"Circle" => CircleMatcher,
"Square" => SquareMatcher,
"Triangle" => TriangleMatcher,
};
myMatcher.store(myMatcher.parse(inputFile));

但我想不出任何一致的方法来定义 Matcher struct/type/trait/whatever 而不违反类型检查器的约束。有可能做这种动态的事情吗?这是不是一个好主意?我很想在这里了解一些好的模式。

谢谢!

最佳答案

好的,我会尽量回答你的问题:

[is it] possible to avoid repeating the "parse-then-store" logic in every branch

答案是肯定的,但是你需要抽象出独特的部分并提取出共同的部分。我稍微改变了你的问题以获得一个更简单的例子。在这里,我们仅根据形状类型解析单个整数。

我们创建了一个新结构 Foo,它包含“将 u32 更改为某种类型,然后保留它们的列表”的概念。为此,我们引入了两个通用部分 - T,我们持有的东西的类型,以及 F,一种转换 u32 的方法进入那种类型。

为了获得一定的灵 active ,我还创建并实现了一个特征 ShapeMatcher。这使我们能够以通用方式获取对 Foo 的特定实例的引用 - trait 对象。如果不需要,您可以将特征内联回 Foo 并将 match_it 调用内联到 if 的分支中.这在 Returning and using a generic type with match 中有进一步描述。 .

#[derive(Debug)]
struct Circle(u32);
#[derive(Debug)]
struct Square(u32);

struct Foo<T, F> {
db: Vec<T>,
matcher: F,
}

impl<T, F> Foo<T, F>
where F: Fn(u32) -> T
{
fn new(f: F) -> Foo<T, F> { Foo { db: Vec::new(), matcher: f } }
}

trait ShapeMatcher {
fn match_it(&mut self, v: u32);
}

impl<T, F> ShapeMatcher for Foo<T, F>
where F: Fn(u32) -> T
{
fn match_it(&mut self, v: u32) {
let x = (self.matcher)(v);
self.db.push(x);
}
}

fn main() {
let mut circle_matcher = Foo::new(Circle);
let mut square_matcher = Foo::new(Square);

for &(shape, value) in &[("circle", 5),("circle", 42),("square", 9)] {
let matcher: &mut ShapeMatcher =
if shape == "circle" { &mut circle_matcher }
else { &mut square_matcher };

matcher.match_it(value);
}

println!("{:?}", circle_matcher.db);
println!("{:?}", square_matcher.db);
}

关于polymorphism - 在 Rust 匹配表达式中保持 DRY,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28751001/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com