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

Gab*_*ele 5 polymorphism traits dispatch rust trait-objects

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

\n\n

考虑以下特征

\n\n
trait Function {\n    fn value(&self, arg: &[f64]) -> f64;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

和两个实现它的结构:

\n\n
struct Add {}\n\nstruct Multiply {}\n\nimpl Function for Add {\n    fn value(&self, arg: &[f64]) -> f64 {\n        arg[0] + arg[1]\n    }\n}\n\nimpl Function for Multiply {\n    fn value(&self, arg: &[f64]) -> f64 {\n        arg[0] * arg[1]\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

在我的main()函数中,我想将Add\xc2\xa0and的两个实例分组Multiply到一个向量中,然后调用该value方法。以下作品:

\n\n
fn main() {\n    let x = vec![1.0, 2.0];\n    let funcs: Vec<&dyn Function> = vec![&Add {}, &Multiply {}];\n\n    for f in funcs {\n        println!("{}", f.value(&x));\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

也是如此:

\n\n
fn main() {\n    let x = vec![1.0, 2.0];\n    let funcs: Vec<Box<dyn Function>> = vec![Box::new(Add {}), Box::new(Multiply {})];\n\n    for f in funcs {\n        println!("{}", f.value(&x));\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

有没有更好/更简洁的方法?我可以解决将实例包装在 a 中的问题吗Box?在这种情况下,特质对象的要点是什么?

\n

Pet*_*all 4

有没有更好/更简洁的方法?

确实没有办法让这个变得不那么冗长。由于您使用的是特征对象,因此您需要告诉编译器向量的项目是dyn Function而不是具体类型。编译器不能仅仅推断您指的是dyn Function特征对象,因为可能存在其他特征,Add并且Multiply两者都实现。

您无法抽象出对Box::new两者的调用。为了实现这一点,您必须以某种方式映射异构集合,这在 Rust 中是不可能的。但是,如果您经常编写此内容,您可能会考虑为每个具体添加辅助构造函数impl

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

    fn new_boxed() -> Box<Add> {
        Box::new(Add::new())
    }
}
Run Code Online (Sandbox Code Playgroud)

尽可能包含new构造函数是惯用的做法,但包含替代的便利构造函数也很常见。

这使得向量的构造噪音较小:

let funcs: Vec<Box<dyn Function>> = vec!(Add::new_boxed(), Multiply::new_boxed()));
Run Code Online (Sandbox Code Playgroud)

在这种情况下,特质对象的要点是什么?

使用动态调度总是会对性能造成一些影响。如果所有对象都是同一类型,它们可以密集地打包在内存中,这样迭代速度会快得多。一般来说,我不会太担心这一点,除非您正在创建一个库箱,或者您确实想挤出最后纳秒的性能。