Rust:向量中结构的多态调用

时间:2018-12-22 16:17:51

标签: rust polymorphism traits dispatch trait-objects

我是Rust的一名新手,我试图对这种语言的基础有所了解。

考虑以下特征

trait Function {
    fn value(&self, arg: &[f64]) -> f64;
}

和两个实现它的结构:

struct Add {}

struct Multiply {}

impl Function for Add {
    fn value(&self, arg: &[f64]) -> f64 {
        arg[0] + arg[1]
    }
}

impl Function for Multiply {
    fn value(&self, arg: &[f64]) -> f64 {
        arg[0] * arg[1]
    }
}

在我的main()函数中,我想将AddMultiply的两个实例组合在一个向量中,然后调用value方法。以下作品:

fn main() {
    let x = vec![1.0, 2.0];
    let funcs: Vec<&dyn Function> = vec![&Add {}, &Multiply {}];

    for f in funcs {
        println!("{}", f.value(&x));
    }
}

也是如此:

fn main() {
    let x = vec![1.0, 2.0];
    let funcs: Vec<Box<dyn Function>> = vec![Box::new(Add {}), Box::new(Multiply {})];

    for f in funcs {
        println!("{}", f.value(&x));
    }
}

有没有更好/更详细的方法?我可以解决将实例包装在Box中的问题吗?在这种情况下,带有特征对象的外卖是什么?

1 个答案:

答案 0 :(得分:1)

  

有没有更好/更详细的方法?

实际上没有一种方法可以使它变得不那么冗长。由于您正在使用特征对象,因此需要告诉编译器,向量的项是dyn Function而不是具体类型。编译器不能仅仅推断出您的意思是dyn Function个特征对象,因为AddMultiply可能还具有其他特征。

您也不能抽象出对Box::new的调用。为此,您必须以某种方式映射到异构集合,这在Rust中是不可能的。但是,如果您正在编写大量内容,则可以考虑为每个具体的impl添加辅助构造函数:

impl Add {
    fn new() -> Add {
        Add {}
    }

    fn new_boxed() -> Box<Add> {
        Box::new(Add::new())
    }
}

在任何可能的地方都包含new构造函数是很习惯的做法,但通常也包括其他便利构造函数。

这使向量的构造噪音更少:

let funcs: Vec<Box<dyn Function>> = vec!(Add::new_boxed(), Multiply::new_boxed()));
  

在这种情况下,带有特征对象的外卖是什么?

使用动态分派始终会降低性能。如果所有对象都是同一类型,则可以将它们密集地包装在内存中,这样可以更快地进行迭代。通常,除非您要创建库箱,或者您真的想挤出性能的最后一纳秒,否则我不会对此太担心。