Gab*_*ele 5 polymorphism traits dispatch rust trait-objects
我是 Rust 的新手,我正在尝试了解该语言的基础知识。
\n\n考虑以下特征
\n\ntrait Function {\n fn value(&self, arg: &[f64]) -> f64;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n和两个实现它的结构:
\n\nstruct 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
方法。以下作品:
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\nfn 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
?在这种情况下,特质对象的要点是什么?
有没有更好/更简洁的方法?
确实没有办法让这个变得不那么冗长。由于您使用的是特征对象,因此您需要告诉编译器向量的项目是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)
在这种情况下,特质对象的要点是什么?
使用动态调度总是会对性能造成一些影响。如果所有对象都是同一类型,它们可以密集地打包在内存中,这样迭代速度会快得多。一般来说,我不会太担心这一点,除非您正在创建一个库箱,或者您确实想挤出最后纳秒的性能。