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

5

我是一名 Rust 的新手,正在尝试了解该语言的基础知识。

考虑以下 trait

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个回答

3
有没有更好/不那么冗长的方法?
实际上没有办法使这个过程更简洁。由于你使用特质对象,你需要告诉编译器向量项是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()));

在这种情况下,特质对象有什么值得注意的地方?

使用动态分派总会带来一些性能损失。如果您的所有对象都是相同类型,则它们可以在内存中密集打包,这对于迭代可能更快。通常,除非您正在创建库箱或者真的想要挤出最后一纳秒的性能,否则不必过于担心。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接