如何在向量中存储实现相同特征的不同类型并调用它们的通用函数?

How do I store different types that implement the same trait in a vector and call common functions on them?

我正在学习 Rust,但在实现多态性方面遇到困难。我想使用数组来存储 CircleTest.

trait Poli {
    fn area(&self) -> f64;
}

struct Circle {
    x:      f64,
    y:      f64,
    radius: f64,
}

impl Circle {
    fn new (xx: f64, yy: f64, r: f64) -> Circle{
        Circle{ x: xx, y: yy, radius: r }
    }
}

impl Poli for Circle {
   fn area(&self) -> f64 {
       std::f64::consts::PI * (self.radius * self.radius)
   }
}

struct Test {
    x:      f64,
    y:      f64,
    radius: f64,
    test:   f64,
}

impl Test {
    fn new (xx: f64, yy: f64, r: f64, t: f64) -> Circle{
        Test{ x: xx, y: yy, radius: r, test: t, }
    }
}

impl Poli for Test {
    fn area(&self) -> f64 {
        std::f64::consts::PI * (self.radius * self.radius)
    }
}

我不知道如何制作一个向量来存储具有相同类型的类型trait:

let cir  = Circle::new(10f64, 10f64, 10f64);
let test = Test::new(10f64, 10f64, 10f64, 10f64);

//let mut vec: Vec<Poli> = Vec::new();   <---

我想迭代向量并从特征调用函数。有什么办法可以做到这一点,或者有其他选择吗?

我读了 the trait object documentation 但我认为这不是我想要的。

page you linked to 中所述,您需要将 Poli 实现结构存储为 Vec<&Poli>Vec<Box<Poli>>,具体取决于您是否想要拥有值或仅存储参考:

// Owned
let circle = Circle::new(10f64, 10f64, 10f64);
let test = Test::new(10f64, 10f64, 10f64, 10f64);

let polis = vec![Box::new(circle) as Box<Poli>, Box::new(test) as Box<Poli>];

for poli in polis {
    println!("{}", poli.area());
}

// Reference
let circle = Circle::new(10f64, 10f64, 10f64);
let test = Test::new(10f64, 10f64, 10f64, 10f64);

let polis = vec![&circle as &Poli, &test as &Poli];

for poli in polis {
    println!("{}", poli.area());
}

输出

314.1592653589793
314.1592653589793
314.1592653589793
314.1592653589793

Demo

之后,我玩了一下,发现这种方式很适合我。我是 Rust 的新手,我不知道这是否显而易见,但我会把它留在这里以帮助其他人。

let circle = Circle::new(10f64, 10f64, 10f64);
let test   = Test::new(10f64, 10f64, 10f64, 10f64);

let mut vec: Vec<&Poli> = Vec::<&Poli>::new();
    vec.push(&circle);
    vec.push(&test);

for v in vec {
    println!("new {}", v.area());
}

Demo